在何种情况下创建一个函数对象比使用lambda表达式更合适?
我知道我的问题与何时使用lambda而不是函数对象的问题实质上是相反的,但我无法想象在实践中存在一种情况,其中函数对象会优先于lambda。 你有什么想法吗?
在何种情况下创建一个函数对象比使用lambda表达式更合适?
我知道我的问题与何时使用lambda而不是函数对象的问题实质上是相反的,但我无法想象在实践中存在一种情况,其中函数对象会优先于lambda。 你有什么想法吗?
一个 lambda 是一个函数对象(functor)- 它只是用更短的语法定义而已。
问题在于,这种语法有局限性。它并不总能让你以最高效和灵活的方式解决问题 - 或者根本无法解决。直到 C++14,operator()
甚至都不能是一个模板。
此外,lambda 只有一个 operator()
。你无法提供多个重载来区分参数类型。
struct MyComparator
{
bool operator()( int a, int b ) const {return a < b;}
bool operator()( float a, float b ) const {return /*Some maths here*/;}
};
闭包对象参数的类型或值类别也可以传递,你也可以不定义特殊成员函数,包括构造函数和析构函数——如果一个函数对象应该负责资源,怎么办呢?
另一个问题是lambda表达式不能递归调用。当然,普通函数(包括运算符函数)可以。
此外,需要考虑lambda表达式在关联容器中作为比较器或在智能指针中作为删除器使用时不太方便:你不能直接将闭包类型作为模板参数传递,并且需要从另一个闭包对象构造容器成员(闭包类型没有默认构造函数!)。对于块作用域的map,这并不是太麻烦:
auto l = [val] (int a, int b) {return val*a < b;};
std::map<int, int, decltype(l)> map(l);
现在,如果你的map
是一个数据成员会发生什么?在构造函数的初始化列表中需要什么模板参数、什么初始化器?你必须使用另一个静态数据成员——但由于你必须在类定义之外定义它,这可能会被认为很丑陋。
总而言之:Lambda表达式并不适用于更复杂的情况,因为它们不是为此而设计的。它们提供了一种简短和简洁的方式来创建简单的函数对象,用于相应地简单的情况。
*this
是一个&&
的重载!而且谁不想在他们的函数对象上有rvalue重载呢? - Yakk - Adam Nevraumontstd :: function
中)并在捕获列表中引用自身的引用。实用吗?不太可能,更不用说您无法像这样返回lambda(引用本地变量),但从技术上讲是可能的。 - Jiří Pospíšil当我需要使用多个实例时,我会考虑使用函数对象而不是lambda表达式。
我能想到两种情况:
当函数对象携带内部状态时,函数对象存在着非平凡的生命周期问题。它在使用之间保留了“某些东西”。
当你必须在各个地方使用相同的代码时,将其编写并保持为一个独立头文件中的函数对象可能是从维护角度考虑的好方法。
lambda表达式不能在未求值的上下文中使用。一个特别假设的例子来自于Shafik's的回答:
因此,即使具有相同语法的 lambda 也不能替代另一个 lambda。在这种情况下,函数对象将起作用。
In many cases it just useless since each lambda has a unique type, the hypothetical example given:
template<typename T, typename U> void g(T, U, decltype([](T x, T y) { return x + y; }) func); g(1, 2, [](int x, int y) { return x + y; });
The type of the lambda in the declaration and the call are different(by definition) and therefore this can not work.
std::function
基本上是一个高级的函数对象。当函数对象更加复杂时,与 lambda 表达式相比,函数对象尤其有用。 - Cornstalks