何时在 lambda 上使用函子

When to use functors over lambdas

本文关键字:lambda 何时      更新时间:2023-10-16

是否有一种情况是创建函子比使用 lambda 更有意义?

我知道我的问题实际上与何时使用lambda而不是函子相反,但是我想不出在实践中哪种情况会更喜欢函子而不是lambda。对此有什么想法吗?

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

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

lambda 的另一个问题是它们不能递归。当然,正常功能(包括算子功能(也可以。

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

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

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

总而言之:Lambda 对更复杂的场景没有用,因为它们不是为它们而生的。它们提供了一种简短而简洁的方法,用于为相应的简单情况创建简单的函数对象。

我会考虑在 lambda 上使用函子,当我

  • 需要多个实例。
  • 必须进行高级资源处理。
  • 需要将函子称为类型。 例如,将其作为模板参数传递。
  • (相关(可以为类型(与实例相反(提供一个有意义且通常有用的名称。
  • 发现当拆分为子函数时,逻辑可以写得更干净。 在 lambda 中,我们必须将所有内容写入单个函数。

我可以想到两种情况:

    当函子
  1. 携带内部状态时,因此函子存在一个不平凡的生命周期问题。它在使用之间保持"某些东西">

  2. 当您必须到处使用相同的代码时,从维护的角度来看,将其编写并保留为自己的标头中的函子可能是一个好主意

lambda 不能在未计算的上下文中使用。一个特别做作的例子是从沙菲克的回答中窃取的:

  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 类型为 不同(根据定义(,因此这行不通。

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