【发布时间】:2013-04-16 03:35:51
【问题描述】:
我是这个概念的新手,但是当我寻找差异时,仿函数的好处是它们能够在内部存储值并从构造中初始化这些值,但是普通函数也以相同的方式工作,只是它们占据了所有函数调用时的整体参数。很可能我在某些方面是错误的,但函子相对于普通函数的诀窍和好处在哪里
【问题讨论】:
-
苹果和水果有什么区别?
我是这个概念的新手,但是当我寻找差异时,仿函数的好处是它们能够在内部存储值并从构造中初始化这些值,但是普通函数也以相同的方式工作,只是它们占据了所有函数调用时的整体参数。很可能我在某些方面是错误的,但函子相对于普通函数的诀窍和好处在哪里
【问题讨论】:
核心区别在于函子定义的是类型而不是函数。即使是无状态函子(没有任何附加数据)也可以利用这一点。例如考虑在排序算法中使用std::less:
template <typename Iterator, typename Comparator>
sort(Iterator begin, Iterator end, Comparator c) {
...
if (c(*begin,*end)) { ...
...
}
称为sort(v.begin(), v.end(), std::less<int>());。当函数被调用时,std::less<int> 的实例被创建并传递给模板。因为它是无状态的,所以传递函数的成本几乎为零。在函数内部,调用c(a,b)被确定为调用c.operator()(a,b),编译器知道类型。它可以有效地内联调用(在这种情况下很简单)并用一条比较指令替换它。
另一方面,等效的 C 函数 qsort 采用函数指针(不能按值传递函数)。在qsort内部,编译器不知道调用的函数是什么,也不能内联,所以每次比较都要进行一次函数调用。
Functor 既可以添加额外的信息,以后可以在调用的地方使用(这对于普通函数是不可能的),也可以传递额外的信息,例如提供需要调用的信息(相同的行为可以是获得,但会影响性能)或其他附加信息(类型可以具有嵌套类型/typedef,用于特征检查的信息......)
【讨论】:
std::less 确实是无状态的,但并不要求可调用对象是无状态的。有状态对象使用起来有点棘手,因为无法保证它们在何处以及多久被处理一次。因此,分阶段的可调用对象通常会保存指向其状态的指针,而不是直接保存状态。
普通函数,独立函数或成员函数,只有在调用函数时将传递它们的参数。所以没有办法向函数传递额外的数据。
这与函子不同。函子是对象的一个实例,因此确实可以存储传递给其构造函数的数据(在传递函子时使用)。
对于 C++11,事情有点混乱,因为 lambdas 还可以通过使用捕获来“存储”(技术上不正确的词)值。或者使用std::bind,它允许您在实际调用可调用对象时将值绑定为参数。
【讨论】: