什么是 lambda 表达式
一个 lambda 表达式提供一个简明的方式来创建简单的功能的对象。lambda 表达式是一个 prvalue,其结果对象称为闭包对象 ,其行为类似于函数对象。
“lambda 表达”这个名字起源于 lambda 演算 ,这是一种数学形式主义,由 Alonzo Church 于 20 世纪 30 年代发明,旨在研究逻辑和可计算性问题。Lambda 演算是 LISP的基础, LISP是一种函数式编程语言。与 lambda 演算和 LISP 相比,C++ lambda 表达式共享未命名的属性,并从周围的上下文中捕获变量,但它们缺乏操作和返回函数的能力。
lambda 表达式通常用作带有可调用对象的函数的参数。这可能比创建一个命名函数更简单,该函数仅在作为参数传递时使用。在这种情况下,lambda 表达式通常是首选,因为它们允许内联定义函数对象。
lambda 通常由三部分组成:捕获列表 []
,可选参数列表 ()
和 body {}
,所有这些都可以为空:
[](){} // An empty lambda, which does and returns nothing
捕获列表
[]
是捕获列表。默认情况下,lambda 无法访问封闭范围的变量。捕获变量使其可以在 lambda 中访问,可以是副本, 也可以是引用 。捕获的变量成为 lambda 的一部分; 与函数参数相比,它们在调用 lambda 时不必传递。
int a = 0; // Define an integer variable
auto f = []() { return a*9; }; // Error: 'a' cannot be accessed
auto f = [a]() { return a*9; }; // OK, 'a' is "captured" by value
auto f = [&a]() { return a++; }; // OK, 'a' is "captured" by reference
// Note: It is the responsibility of the programmer
// to ensure that a is not destroyed before the
// lambda is called.
auto b = f(); // Call the lambda function. a is taken from the capture list and not passed here.
参数列表
()
是参数列表,与常规函数几乎相同。如果 lambda 不带参数,则可以省略这些括号(除非你需要声明 lambda mutable
)。这两个 lambdas 是等价的:
auto call_foo = [x](){ x.foo(); };
auto call_foo2 = [x]{ x.foo(); };
Version >= C++ 14
参数列表可以使用占位符类型 auto
而不是实际类型。通过这样做,此参数的行为类似于函数模板的模板参数。当你想要在通用代码中对向量进行排序时,以下 lambdas 是等效的:
auto sort_cpp11 = [](std::vector<T>::const_reference lhs, std::vector<T>::const_reference rhs) { return lhs < rhs; };
auto sort_cpp14 = [](const auto &lhs, const auto &rhs) { return lhs < rhs; };
功能体
{}
是正文,与常规函数相同。
叫一个 lambda
lambda 表达式的结果对象是一个闭包 ,可以使用 operator()
调用(与其他函数对象一样):
int multiplier = 5;
auto timesFive = [multiplier](int a) { return a * multiplier; };
std::out << timesFive(2); // Prints 10
multiplier = 15;
std::out << timesFive(2); // Still prints 2*5 == 10
退货类型
默认情况下,推导出 lambda 表达式的返回类型。
[](){ return true; };
在这种情况下,返回类型是 bool
。
你还可以使用以下语法手动指定返回类型:
[]() -> bool { return true; };
可变的 Lambda
默认情况下,lambda 中的值捕获的对象是不可变的。这是因为生成的闭包对象的 operator()
默认为 const
。
auto func = [c = 0](){++c; std::cout << c;}; // fails to compile because ++c
// tries to mutate the state of
// the lambda.
使用关键字 mutable
可以允许修改,这使得更近的对象的 operator()
非 const
:
auto func = [c = 0]() mutable {++c; std::cout << c;};
如果与返回类型一起使用,mutable
就会出现在它之前。
auto func = [c = 0]() mutable -> int {++c; std::cout << c; return c;};
一个例子来说明 lambda 的有用性
在 C++ 11 之前:
Version < C++ 11
// Generic functor used for comparison
struct islessthan
{
islessthan(int threshold) : _threshold(threshold) {}
bool operator()(int value) const
{
return value < _threshold;
}
private:
int _threshold;
};
// Declare a vector
const int arr[] = { 1, 2, 3, 4, 5 };
std::vector<int> vec(arr, arr+5);
// Find a number that's less than a given input (assume this would have been function input)
int threshold = 10;
std::vector<int>::iterator it = std::find_if(vec.begin(), vec.end(), islessthan(threshold));
从 C++ 11 开始:
Version >= C++ 11
// Declare a vector
std::vector<int> vec{ 1, 2, 3, 4, 5 };
// Find a number that's less than a given input (assume this would have been function input)
int threshold = 10;
auto it = std::find_if(vec.begin(), vec.end(), [threshold](int value) { return value < threshold; });