我最近发现在C ++中你可以以一种奇怪的方式重载“函数调用”操作符,你必须编写两对括号来执行此操作:
class A {
int n;
public:
void operator ()() const;
};
然后以这种方式使用它:
A a;
a();
什么时候有用?
答案 0 :(得分:27)
这可以用来创建"functors",这些对象的功能类似于:
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
。上面链接的维基百科文章提供了更多实质性的例子。
答案 1 :(得分:17)
在开始使用模板之前,使用operator()几乎没有语法上的好处。但是在使用模板时,你可以用同样的方式处理实际函数和函子(作为函数的类)。
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) );
答案 2 :(得分:5)
使用模板实现的算法并不关心被调用的东西是函数还是函子,它关心语法。标准的(例如for_each())或您自己的。函子可以拥有状态,并在调用时执行各种操作。函数只能具有静态局部变量或全局变量的状态。
答案 3 :(得分:1)
如果你正在创建一个封装函数指针的类,这可能会使用法更加明显。
答案 4 :(得分:1)
编译器还可以内联函子和函数调用。但是,它不能内联函数指针。这样,使用函数调用操作符可以显着提高性能,例如使用标准C ++库算法。
答案 5 :(得分:0)
例如,用于实现生成器:
// 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;
}
答案 6 :(得分:0)
我看到了一种可能的异国用途:
假设您具有未知类型的对象,并且必须声明另一个相同类型的变量,如下所示:
auto c=decltype(a*b)(123);
当这种模式广泛使用时,decltype变得非常烦人。 当使用一些智能类型系统时,会发生这种情况,该系统会根据参数的类型自动创建函数和运算符的结果类型。
现在,如果该类型系统的每种类型的每个专业配备
operator()
的神奇定义是这样的:
template<????> class Num<???>{
//specific implementation here
constexpr auto operator()(auto...p){return Num(p...);}
}
decltype()
不再需要,您只需编写即可:
auto c=(a*b)(123);
因为对象的operator()重定向到其自身类型的构造函数。