什么时候在lambda上使用仿函数

时间:2014-12-02 18:05:36

标签: c++ c++11 lambda functor

是否存在创建仿函数比使用lambda更有意义的情况?

我知道我的问题实际上与when to use a lambda over a functor相反,但我无法想到实际情况,其中一个仿函数是首选的而不是lambda。有什么想法吗?

4 个答案:

答案 0 :(得分:40)

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*/;}
};

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

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

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

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

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

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

答案 1 :(得分:15)

当我

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

答案 2 :(得分:7)

我能想到两个案例:

  1. 当仿函数携带内部状态时,仿函数存在一个非平凡的生命周期问题。它在用途

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

答案 3 :(得分:5)

lambda不能是used in an unevaluated context。一个特别人为的例子是Shafik's回答:

  
      
  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; });
    
         

    声明和调用中lambda的类型   不同(按照定义),因此无法使用。

  2.   

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