重载“函数调用”运算符有什么用处?

28

我最近发现在C++中可以重载"函数调用"运算符, 这种方式看起来很奇怪,因为你需要写两对括号才能这样做:

class A { 
  int n;
public: 
  void operator ()() const; 
};

然后像这样使用:

A a;
a();

什么时候这个有用?


3
了解函数对象。http://zh.wikipedia.org/wiki/函数对象 - AnT stands with Russia
7个回答

36

可以使用这个来创建"函数对象",它们就像函数一样的对象:

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。上面链接到的维基百科文章提供了更多实质性的示例。


3
使用函数对象的主要原因是在C++中实现高阶函数。 - Harold L
2
你可以将其扩展,例如第一次调用时乘以m,第二次乘以m+1等。普通函数无法在调用之间保存任何状态信息,但是functor可以。 - Tyler
4
你可以在函数中使用静态变量来提供状态(或全局变量 - 令人不安)。但这两者都很丑陋且容易出错。(我会使用一个函数对象代替,但这也是可能的) - Michael Anderson

21

在不使用模板时,使用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) );

是的,类似函数的对象在您具有足够弱的类型时确实非常有用。C++没有这个功能,但模板可以实现。 - Adrian Ratnapala

6

使用模板实现的算法并不关心被调用的是函数还是函数对象,它只关心语法。无论是标准函数(例如for_each())还是自定义函数都可以。而且函数对象可以拥有状态,在被调用时可以执行各种操作。函数只能通过静态局部变量或全局变量来维护状态。


1
例如,实现生成器的示例:
// 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;
}

1
如果你正在创建一个封装函数指针的类,这样做可能会使使用更加明显。

1
编译器还可以内联函数对象和函数调用。但它无法内联函数指针。因此,当使用标准C ++库算法时,使用函数调用运算符可以显著提高性能。

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()重定向到其自身类型的构造函数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接