目录
0.前言
在C++中,lambda表达式提供了一种定义匿名函数对象的方式。这些函数对象可以捕获它们所在作用域中的变量,并且可以作为参数传递给其他函数,或者赋值给函数指针和函数对象。lambda表达式的语法灵活,可以非常方便地定义和使用。
1.Lambda表达式的基本语法
[capture](parameters) mutable -> return_type {
// 函数体
}
1.1 语法解析
-
capture(捕获列表):指定哪些外部变量可以在lambda表达式体内被访问。捕获列表可以是以下几种形式之一:
[]
:不捕获任何外部变量。[x, &y]
:按值捕获x
,按引用捕获y
。[&]
:捕获所有外部变量,以引用的方式。[=]
:捕获所有外部变量,以值的方式。[=, &z]
:首先捕获所有外部变量以值的方式,但随后指定z
以引用的方式捕获(这实际上会覆盖z
的按值捕获)。[&, x]
:首先捕获所有外部变量以引用的方式,但随后指定x
以值的方式捕获(注意,这通常不是很有用,因为x
已经以引用的方式在作用域中可用了)。
-
parameters(参数列表):与普通函数的参数列表相同,指定了lambda表达式接受哪些参数。参数列表是可选的,如果不写,则lambda表达式是一个无参函数。
-
mutable(可选):如果指定了
mutable
关键字,则lambda表达式体内的代码可以修改以值捕获的方式捕获的变量。 -
return_type(可选):指定了lambda表达式的返回类型。在C++11及以后的版本中,如果函数体中有返回语句,并且这些返回语句的类型相同,则编译器可以自动推导返回类型(称为返回类型推导)。如果函数体中没有返回语句(即返回类型为
void
),或者需要显式指定返回类型(例如,当存在多条返回语句且这些语句的返回类型不同时),则需要显式指定返回类型。 -
函数体:包含了需要执行的代码。
2.示例
2.1 无参数、无捕获的lambda表达式
auto func = []() {
std::cout << "Hello, lambda!" << std::endl;
};
func(); // 输出: Hello, lambda!
2.2 有参数、有捕获的lambda表达式
int x = 10;
auto printXPlusY = [x](int y) {
std::cout << x + y << std::endl;
};
printXPlusY(5); // 输出: 15
注意,这里的x
是按值捕获的,因此在lambda表达式体内对x
的修改不会影响原始变量x
。
修改值捕获的变量(使用mutable)
int counter = 0;
auto increment = [counter]() mutable {
++counter;
std::cout << counter << std::endl;
};
increment(); // 输出: 1
increment(); // 输出: 2
2.3捕获所有变量(使用&
或=
)
int a = 1, b = 2;
auto sum = [&]() {
return a + b;
};
std::cout << sum() << std::endl; // 输出: 3,a和b都是按引用捕获的
// 或者
auto sumByValue = [=]() {
return a + b; // 这里使用的是a和b的副本
};
// 注意:如果a或b在lambda表达式被调用之前被修改,sumByValue的结果将不会反映这些修改
注意事项
- 捕获列表中的变量必须是可见的,即它们必须在lambda表达式定义的作用域内。
- 捕获的变量(特别是按值捕获的变量)的生命周期必须至少与lambda表达式的生命周期一样长,否则可能会导致悬垂引用或未定义行为。
- 在多线程环境中使用lambda表达式时,需要特别注意数据竞争和同步问题,特别是当lambda表达式捕获了外部变量并以引用的方式访问它们时。