C++11 的一大亮点就是引入了 $\text{Lambda}$ 表达式。利用 $\text{Lambda}$ 表达式,可以方便的定义和创建匿名函数,以此简化代码。


声明

$\text{Lambda}$ 表达式的一般声明格式如下:

[ captures ] ( params ) specifiers(可选) -> ret(可选) { body }

当然还有若干种不完整声明,常见的如下:

  1. [ captures ] ( params ) -> ret { body }
  2. [ captures ] ( params ) { body }
  3. [ 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 以值的形式捕获,其余变量以引用形式捕获。

引用

最后修改:2019 年 07 月 30 日
如果觉得我的文章对你有用,请随意赞赏