1. lambda的声明
Lambda表达式完整的声明格式如下:
[capture list] (params list) mutable exception-> return type { function body }
各项具体含义如下:
capture list:捕获外部变量列表
params list:形参列表
mutable指示符:用来说用是否可以修改捕获的变量
exception:异常设定
return type:返回类型
function body:函数体
“不完整”的Lambda表达式,常见的有以下几种:
- [capture list] (params list) -> return type {function body}
- [capture list] (params list) {function body}
- [capture list] {function body}
编译器可以根据以下规则推断出Lambda表达式的返回类型:
(1):如果function body中存在return语句,则该Lambda表达式的返回类型由return语句的返回类型确定;
(2):如果function body中没有return语句,则返回值为void类型。
2. 捕获外部变量
Lambda表达式可以使用其可见范围内的外部变量,但必须明确声明(明确声明哪些外部变量可以被该Lambda表达式使用)。那么,在哪里指定这些外部变量呢?Lambda表达式通过在最前面的方括号[]来明确指明其内部可以访问的外部变量,这一过程也称过Lambda表达式“捕获”了外部变量。
#include <iostream>
using namespace std;
int main()
{
int a = 123;
auto f = [a] { cout << a << endl; };
f(); // 输出:123
//或通过“函数体”后面的‘()’传入参数
auto x = [](int a){cout << a << endl;}(123);
}
隐式捕获
值捕获和引用捕获都需要我们在捕获列表中显示列出Lambda表达式中使用的外部变量。除此之外,我们还可以让编译器根据函数体中的代码来推断需要捕获哪些变量,这种方式称之为隐式捕获。隐式捕获有两种方式,分别是[=]和[&]。[=]表示以值捕获的方式捕获外部变量,[&]表示以引用捕获的方式捕获外部变量。
隐式值捕获示例:
int main()
{
int a = 123;
auto f = [=] { cout << a << endl; }; // 值捕获
f(); // 输出:123
}
隐式引用捕获示例:
int main()
{
int a = 123;
auto f = [&] { cout << a << endl; }; // 引用捕获
a = 321;
f(); // 输出:321
}
修改捕获变量
前面我们提到过,在Lambda表达式中,如果以传值方式捕获外部变量,则函数体中不能修改该外部变量,否则会引发编译错误。那么有没有办法可以修改值捕获的外部变量呢?这是就需要使用mutable关键字,该关键字用以说明表达式体内的代码可以修改值捕获的变量,示例:
int main()
{
int a = 123;
auto f = [a]()mutable { cout << ++a; }; // 不会报错
cout << a << endl; // 输出:123
f(); // 输出:124
}