我最近发现在C++中可以重载"函数调用"运算符, 这种方式看起来很奇怪,因为你需要写两对括号才能这样做:
class A {
int n;
public:
void operator ()() const;
};
然后像这样使用:
A a;
a();
什么时候这个有用?
我最近发现在C++中可以重载"函数调用"运算符, 这种方式看起来很奇怪,因为你需要写两对括号才能这样做:
class A {
int n;
public:
void operator ()() const;
};
然后像这样使用:
A a;
a();
什么时候这个有用?
可以使用这个来创建"函数对象",它们就像函数一样的对象:
class Multiplier {
public:
Multiplier(int m): multiplier(m) {}
int operator()(int x) { return multiplier * x; }
private:
int multiplier;
};
Multiplier m(5);
cout << m(4) << endl;
上面的代码输出20
。上面链接到的维基百科文章提供了更多实质性的示例。
在不使用模板时,使用operator()只是一种语法上的改进而已。但是,在使用模板时,您可以将真实函数和functor(充当函数的类)同等对待。
class scaled_sine
{
explicit scaled_sine( float _m ) : m(_m) {}
float operator()(float x) const { return sin(m*x); }
float m;
};
template<typename T>
float evaluate_at( float x, const T& fn )
{
return fn(x);
}
evaluate_at( 1.0, cos );
evaluate_at( 1.0, scaled_sine(3.0) );
使用模板实现的算法并不关心被调用的是函数还是函数对象,它只关心语法。无论是标准函数(例如for_each())还是自定义函数都可以。而且函数对象可以拥有状态,在被调用时可以执行各种操作。函数只能通过静态局部变量或全局变量来维护状态。
// generator
struct Generator {
int c = 0;
virtual int operator()() {
return c++;
}
};
int sum(int n) {
Generator g;
int res = 0;
for( int i = 0; i < n; i++ ) {
res += g();
}
return res;
}
我看到了一个奇特的潜力:
假设你有一个未知类型的对象,并且必须声明另一个相同类型的变量,就像这样:
auto c=decltype(a*b)(123);
operator()
的魔法定义:template<????> class Num<???>{
//specific implementation here
constexpr auto operator()(auto...p){return Num(p...);}
}
decltype()
不再需要,你可以简单地写成:
auto c=(a*b)(123);
因为对象的operator()重定向到其自身类型的构造函数。