为什么要编写一个带有名称的 C++ lambda,以便可以从某个地方调用它?这不会违背 lambda 的初衷吗?在那里写一个函数更好吗?如果没有,为什么?函数会有什么缺点吗?
它的一个用途是让函数访问封闭的范围。
在 C++ 中,我们没有像其他语言那样的嵌套函数。 使用命名的 lambda 可以解决这个问题。 一个例子:
#include <iostream>
int main ()
{
int x;
auto fun = [&] (int y) {
return x + y;
};
std::cin >> x;
int t;
std::cin >> t;
std::cout << fun (fun (t));
return 0;
}
这里,函数
fun
基本上是main
中的嵌套函数,能够访问其局部变量。
我们可以对其进行格式化,使其类似于常规函数,并多次使用它。
使用名称的一个很好的理由是表达意图。然后我们可以检查 lambda 是否做了“正确的事情”,并且读者可以检查意图。给定:
std::string key;
std::map<std::string, int> v;
可以写出以下内容:
std::find_if( v.begin(), v.end(), [&](auto const& elem){ return elem.first == key; } );
但很难判断它是否做了“正确的事”。而如果我们拼写出来:
auto matches_key = [&](auto const& elem){ return elem.first == key; };
std::find_if( v.begin(), v.end(), matches_key );
更清楚的是,我们确实希望进行相等比较,并且提高可读性。
在命名 lamdba 和自由函数之间进行选择时,我认为需要考虑三件事:
您想为可调用对象编写测试和/或在多个翻译单元中重用它吗?如果是,请选择一个自由函数,因为您必须在头文件中声明它并在 lamdba 闭包中捕获变量
在头文件中有点混乱(当然,这是有争议的)。
要求已知类型。因此,您不能接受函数参数和返回类型的前向声明来减少编译时间。
当你的 lambda 本身就是一个递归函数时,你别无选择,只能给它一个名字。此外,
auto
关键字是不够的,您必须使用带有返回类型和参数列表的std::function
来声明它。
下面是返回第 N 个斐波那契数的函数示例:
std::function<int(int)> fibonacci = [&](int n) {
if (n == 0 || n == 1) {
return 1;
} else {
return fibonacci(n - 1) + fibonacci(n - 2);
}
}
您必须为其指定名称才能使用
&
捕获它。并且 auto
不起作用,因为 lambda 在调用自身之前需要知道它的类型。
这基本上是一个基于意见的问题。这取决于您,无论您喜欢函数还是 lambda,它们都是等效的。当您需要来自周围环境的变量时,lambda 就会发挥作用。您只需捕获它们,而不是将其作为参数传递,这很简洁。
但除此之外,没有什么区别。
在调整 C++ 应用程序时,与匿名/未命名 lambda 相比,命名 lambda 更容易调整/跟踪
我一直认为 lamda 是一件好事——在引入 lamda 之前,我在没有它们的情况下进行了大量的 C++ 编码。因此,在某些方面,我认为围绕它们没有太多应该或不应该的事情。它们可以使用,但可以让您的生活更轻松。
有一次我使用命名的 lamdas 来限定一个函数的范围 - 即 lamda 只会在另一个函数中使用 - 也许它会做一些有点危险的事情,你不希望其他函数访问或者你可能不希望不想污染命名空间。
如果你的 lamda 太长而无法成为简单的单行文字,但你又不希望它成为 如果您的范围之外可用,那么命名的 lamda 是生成整洁且易于阅读的代码的理想方法。
当对一个方法的多次调用使用相同的 lambda 时,您需要按名称引用它。