【问题标题】:How can it be useful to overload the "function call" operator?重载“函数调用”运算符有什么用?
【发布时间】:2011-01-21 22:25:30
【问题描述】:

我最近发现,在 C++ 中,您可以重载“函数调用”运算符,以一种奇怪的方式,您必须编写两对括号才能这样做:

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

然后这样使用:

A a;
a();

什么时候有用?

【问题讨论】:

标签: c++ operator-overloading functor function-object


【解决方案1】:

这可以用来创建"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。上面链接的 Wikipedia 文章提供了更多实质性示例。

【讨论】:

  • 您想要仿函数的主要原因是在 C++ 中具有高阶函数。
  • 您可以将其扩展为,例如,第一次调用时乘以 m,第二次乘以 m+1,等等。普通函数无法在调用之间保存任何状态信息,但函子可以。
  • 好吧,您总是可以在函数中使用静态变量来赋予它状态(或全局变量 - 不寒而栗)。但两者都非常丑陋且容易出错。 (我会使用仿函数......但这是可能的)
【解决方案2】:

在您开始使用模板之前,使用 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) );

【讨论】:

  • 是的;当你有足够弱的类型时,类函数对象确实是最有用的。 C++ 没有,但模板有。
【解决方案3】:

使用模板实现的算法不关心被调用的是函数还是仿函数,它关心的是语法。标准的(例如 for_each())或您自己的。函子可以有状态,在被调用时可以做各种事情。函数只能具有带有静态局部变量或全局变量的状态。

【讨论】:

    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      编译器还可以内联仿函数和函数调用。但是,它不能内联函数指针。这样,在与标准 C++ 库算法一起使用时,使用函数调用运算符可以显着提高性能。

      【讨论】:

        【解决方案6】:

        例如实现生成器:

        // 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;
        }
        

        【讨论】:

          【解决方案7】:

          我看到了另一种异国用途的潜力:

          假设你有一个未知类型的对象,并且必须声明另一个相同类型的变量,像这样:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-08-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多