何时使用基于lambda的仿函数

sir*_*lot 28 c++ lambda functor c++11

有没有一种情况,创建一个仿函数比使用lambda更有意义?

我知道我的问题是有效的反向时,在仿函数使用lambda,但我不认为在实践中的情况下一个仿函数会首选在拉姆达.有什么想法吗?

Col*_*mbo 41

lambda是一个仿函数 - 只是用较短的语法定义的.

问题是这种语法是有限的.它并不总能让您以最有效和最灵活的方式解决问题 - 或者根本无法解决问题.直到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*/;}
};
Run Code Online (Sandbox Code Playgroud)

..或对象参数的值类别(即被调用的闭包对象).您也可以不定义特殊的成员函数,包括构造函数和析构函数 - 如果函子应该负责资源怎么办?

lambdas的另一个问题是它们不能递归.当然,正常的功能(包括操作员功能)可以.

还要考虑lambdas不能用作关联容器的比较器或智能指针的删除器:您不能直接将闭包类型作为模板参数传递,并且需要从另一个闭包对象构造容器成员.(闭包类型没有默认构造函数!).对于一个map不太麻烦的块范围:

auto l = [val] (int a, int b) {return val*a < b;};
std::map<int, int, decltype(l)> map(l);
Run Code Online (Sandbox Code Playgroud)

现在,如果您map数据成员会发生什么?什么模板参数,构造函数初始化列表中的初始化器是什么?您必须使用另一个静态数据成员 - 但是因为您必须在类定义之外定义它,这可能是丑陋的.

总结一下:Lambdas对于更复杂的场景没有用处,因为它们不适用于它们.它们提供了一种简洁明了的方法,可以为相应的简单情况创建简单的函数对象.

  • "lambdas(...)不能递归"这不完全正确,你可以使lambda递归,只是它的类型需要提前知道(例如通过将lambda存储在`std :: function`中)并取捕获列表中对自身的引用.实际的?不是真的,更不用说你不能像这样返回一个lambda(引用本地),但技术上可行. (2认同)

5go*_*der 15

我会考虑在lambda上使用仿函数

  • 想要多个实例.
  • 必须做高级资源处理.
  • 需要将仿函数称为类型.例如,将其作为模板参数传递.
  • (相关的)可以提供一个有意义的和通常是有用的名称的类型(如相对的实例).
  • 发现当分成子功能时,逻辑可以写得更清晰.在lambda中,我们必须将所有内容写入单个函数中.


Sev*_*eux 7

我能想到两个案例:

  1. 当仿函数携带内部状态时,仿函数存在一个非平凡的生命周期问题.它在用途之间保持"某种东西"

  2. 当您必须在整个地方使用相同的代码时,从维护的角度来看,在自己的标题中编写并将其保存为仿函数可能是一个好主意


小智 5

lambda不能在未评估的上下文中使用.从Shafik的回答中偷走了一个特别人为的例子:

  1. 在许多情况下它只是没用,因为每个lambda都有一个独特的类型,假设的例子给出:

    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; });
    
    Run Code Online (Sandbox Code Playgroud)

    声明和调用中lambda的类型是不同的(根据定义),因此这不起作用.

因此,即使是具有相同语法的lambda也不能用来代替另一个.在这种情况下,仿函数将起作用.