11

我看到函数对象经常与 STL 算法一起使用。函数对象是因为这些算法而出现的吗?什么时候在 C++ 中使用函数对象?它有什么好处?

4

7 回答 7

9

正如 jdv 所说,使用函子而不是函数指针,这对于编译器来说更难优化和内联;此外,仿函数的一个基本优点是它们可以轻松地在调用它们1之间保持状态,因此它们可以根据调用它们的其他时间以不同的方式工作,以某种方式跟踪它们使用的参数,...

例如,如果您想将两个整数容器中的所有元素相加,您可以执行以下操作:

struct
{
    int sum;
    void operator()(int element) { sum+=element; }
} functor;
functor.sum=0;
functor = std::for_each(your_first_container.begin(), your_first_container.end(), functor);
functor = std::for_each(your_second_container.begin(), your_second_container.end(), functor);
std::cout<<"The sum of all the elements is: "<<functor.sum<<std::endl;

  1. 实际上,正如 R Samuel Klatchko 在下面指出的那样,它们可以支持多个独立状态,每个 functor 实例一个:
    更准确一点的说法是仿函数可以支持多个独立状态(函数可以通过既不是线程安全也不是可重入的静态/全局变量支持单个状态)。
    函子使您能够使用更复杂的状态,例如共享状态(静态字段)和私有状态(实例字段)。然而,这种进一步的灵活性很少使用。
于 2010-02-28T15:20:54.140 回答
7

通常使用函数对象(函子)代替函数指针。函数指针的问题是编译器通常将它们作为原始指针传递,这使得编译器以后很难内联代码。而且它们更容易提供参数。

于 2010-02-28T15:12:26.960 回答
2

函数对象被设计为允许对 STL 进行强大的抽象层,在这方面它们很棒。

但是,我更喜欢使用boost::bind函数并将其绑定到 STL 算法——通常(尽管不是在对象具有状态的情况下)这似乎是一个更优雅的解决方案。

std::for_each( callback.begin(), callback.end(), 
    boost::bind(&Callback::call(),_1) 
);

此外,另一个即将到来的替代方案是 C++0x 中的 lambda(从 Wikipedia 无耻地窃取的示例):

std::vector<int> someList;
int total = 0;
std::for_each(someList.begin(), someList.end(), [&total](int x) {
  total += x;
});
std::cout << total;

请注意,由于闭包,它们没有绑定关于没有状态的限制。

于 2010-02-28T15:09:38.777 回答
2

函数对象是一个同时也是对象的函数,即它具有状态。普通函数一般没有状态。它们可以通过访问全局变量来模拟具有状态,但随后状态在所有调用中共享。

于 2010-02-28T15:27:01.457 回答
1

我不能说他们为什么会出现——可能只是因为他们可以!

什么时候使用函子?考虑到仿函数只是将您通常放入循环中的代码移动到类的 operator() 中,它们与仅在 while 循环中调用函数没有太大区别……除了使用它们你允许编译器内联代码,你也可以传递一个预先构造的对象,你已经构造了一些状态。后一点使它们非常强大。

将排序算法与 CRT 的 qsort 调用进行比较。他们做同样的事情,只是做的完全不同。

于 2010-02-28T15:18:02.117 回答
1

将函数封装为对象的想法可以追溯到 Lisp 和 Smalltalk。函子的 C++ 思想是 Jim Coplien 在 1991 年出版的Advanced C++ Programming Styles and Idioms一书中的一个章节。STL使用了这个成语并进一步普及了它。

于 2010-02-28T16:37:53.037 回答
1

本文对函数对象进行了深入的研究,以及它如何使代码更强大、更简洁。

于 2013-04-03T02:44:01.843 回答