【问题标题】:Functor - what power do they have over other classes that didn't implement operator ( )Functor - 他们对其他没有实现 operator () 的类有什么权力
【发布时间】:2012-08-26 12:55:37
【问题描述】:

我试图理解函子的“力量”。

好的,所以它们是指向函数的指针,但是它们能做什么其他没有实现operator() 的类不能做?

例如:

#include <iostream>
#include <assert.h>
#include <vector>
using namespace std;


class MultiplyBy
{
    private:
        int factor;

    public:
        MultiplyBy(int x) : factor(x) {}

        int operator () (int other) const
        {
            return factor * other;
        }
};


int main()
{

    MultiplyBy temp(5);
    int myResult = temp(5);  // now myResult holds 25
    cout << myResult << endl;
    return 0;
}

我们带走了他的另一个朋友

class MultiplyOther
{
    private:
        int factor;
    public:
        MultiplyOther(int x) : factor(x) {}
        int invokeMultiplyMe(int _other)
        {
            return _other * factor;
        }
};

然后做同样的事情:

int main()
{
    // MultiplyOther

    MultiplyOther notFunctor(4);
    int myOther = notFunctor.invokeMultiplyMe(3);
    cout << myOther << endl;
    return 0;
}

我们得到:

25
12

那么,函子的真正威力是什么?两个类都保存状态,还是我在这里遗漏了什么?

【问题讨论】:

  • 我认为真正的力量隐藏在 lambdas 中
  • @Mr.Anubis:Lambda 是函子的语法糖,它们没有更多的权力。
  • @interjay 您可以在调用点定义它们,捕获变量等。你能用简单的函子做到这一点而不将它们作为参数等传递吗?
  • @Mr.Anubis:您可以在调用之前定义一个本地类。 lambda 中的变量捕获是将它们存储在类成员中的语法糖。任何可以用 lambda 完成的事情也可以用仿函数完成(尽管它可能更冗长)。反之则不然。

标签: c++ class function pointers functor


【解决方案1】:

一方面,它们具有可以使用的统一签名,例如通过只需要知道它们必须调用某物的算法。

在您的示例中,任何代码都可以使用MultiplyBy 的实例,该代码期望调用采用int 并返回一个(或可从/convertible 构造为int 的类型)。使用您的第二个示例需要代码了解 invokeMultiplyByMe 方法。

请注意,函子根本不是指向函数的指针,如问题中所述。它们是可以使用函数调用语法调用其实例的类。

【讨论】:

  • 啊哈! "Using your second example would require the code to have knowledge of the invokeMultiplyByMe method" 没看到,+1!
  • @ron BTW,我刚刚在你的问题中看到“......它们是指向函数的指针......”。这不是真的。
  • 另外有趣的是:通常函子可以被积极内联,使得诸如 for_each(start, end, functor) 之类的代码通常比 for_each(start, end, func_ptr) 运行得更快
【解决方案2】:

Functor 对类没有任何特殊属性,但它们可以用作具有更高功能的函数。函数通常不能有状态,如果有状态(通过使用静态变量),则状态会在所有函数调用之间共享。\

仿函数具有类的所有属性(尤其是状态),但可以用作函数。一个很好的例子是用于 STL 算法的函子:

class Add
{
  public:
    Add(){sum = 0;};
    void operator()(int i)
    {
        sum += i;
    }
    int getSum(){return sum;};

    private:
    int sum;
}

int main()
{

std::vector<int> vint;
vint.push_back(2);
vint.push_back(3);
vint.push_back(4);
}

Add adder;

adder = std::for_each( vint.begin(); vint.end(), adder);

cout << adder.getSum();

【讨论】:

    【解决方案3】:

    “所以它们是指向函数的指针” - 函数指针和仿函数完全不同。前者只是一个指向原始函数的简单指针。它不持有任何状态。然而,仿函数或函数对象拥有一个状态。 Functor 是定义 operator() 的任何类。因此,该类的任何对象都可以以函数的方式调用。

    来自 C++ 入门的代码 sn-p...

    template<class T>
    class TooBig
    {
        private:
        T cutoff;
        public:
        TooBig(const T & t) : cutoff(t) {}
        bool operator()(const T & v) { return v > cutoff; }
    };
    

    通过这个类,我们可以创建多个具有不同截止值的对象。 太大的截止1(10); TooBig cutOff2(20);

    使用仿函数的最佳位置之一是在模板中。例如,获取列表模板。它有一个 remove_if 函数,用于删除列表中从参数返回 true 的所有值。

    列表列表1; // 假设它有一些值 列出清单2; // 假设它有一些值

    现在,调用 list1.remove_if(cutoff1); // 应用 list1 的所有元素,并删除那些大于 cutOff1 中存储的值的元素。 list2 类似。

    谢谢!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-13
      • 2011-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-14
      相关资源
      最近更新 更多