C++11 的一大亮点就是引入了 $\text{Lambda}$ 表达式。利用 $\text{Lambda}$ 表达式,可以方便的定义和创建匿名函数,以此简化代码。
声明
$\text{Lambda}$ 表达式的一般声明格式如下:
[ captures ] ( params ) specifiers(可选) -> ret(可选) { body }
当然还有若干种不完整声明,常见的如下:
[ captures ] ( params ) -> ret { body }
[ captures ] ( params ) { body }
[ captures ] { body }
解释
- captures:捕获外部变量列表。
- params:形参列表。
- specifiers:指定符序列。C++11 中常用的为
mutable
(允许body
修改以值捕获的参数)。 - ret:返回类型。若省略则由函数的
return
语句所隐含(或如函数不返回任何值则为void
)。 - body:函数体。
捕获外部变量
值捕获
被捕获的变量的值在 $\text{Lambda}$ 表达式创建时通过值拷贝的方式传入,因此随后对该变量的修改不会影响 $\text{Lambda}$ 表达式中的值。
代码示例:
#include <cstdio>
int main() {
int a = 1;
auto f = [a] {printf("%d\n", a);};
a = 2;
f(); // 1
}
引用捕获
类似的,引用捕获后对变量的修改会影响 $\text{Lambda}$ 表达式中的值。我们只需要在变量前面加上一个引用说明符 &
即可。
代码示例:
#include <cstdio>
int main() {
int a = 1;
auto f = [&a] {printf("%d\n", a);};
a = 2;
f(); // 2
}
隐式捕获
我们可以直接让编译器根部函数体中的代码推断需要捕获的变量,称为隐式捕获。隐式捕获有 $2$ 种方式:值捕获和引用捕获,分别以 [=]
和 [&]
表示。
值得提醒的是,在 Google 开源项目风格指南中对于 $\text{Lambda}$ 表达式有如下结论:
禁用默认捕获,捕获都要显式写出来。打比方,比起[=](int x) {return x + n;}
, 您该写成[n](int x) {return x + n;}
才对,这样读者也好一眼看出n
是被捕获的值。
代码示例:
#include <cstdio>
int main() {
int a = 1;
auto f = [=] {printf("%d\n", a);};
auto g = [&] {printf("%d\n", a);};
a = 2;
f(); // 1
g(); // 2
}
混合捕获
$\text{Lambda}$ 表达式除了单纯的值捕获和引用捕获,还支持多种捕获组合使用。主要有如下 $2$ 种写法:
[=, &x]
:变量x
以引用形式捕获,其余变量以传值形式捕获。[&, x]
:变量x
以值的形式捕获,其余变量以引用形式捕获。
2 条评论
Orz
ORZ