Lamada 表达式是 C++11 最重要也是最常用的特性之一。Lamada 来源于函数式编程的概念,也是现代编程语言的一个特点。
一、Lamada 表达式定义
下图展示出了 C++ Lamada 表示的组成部分:
其中:
① 指明捕获列表。
② 指明参数列表。
③ mutable
可选项。和常规的 mutable 用法类似,即当 lamada 表达式参数是 const 时,使用mutable
可以取消这种 const。
④ throw
可选项。可以使用noexcept
指明/约束表达式内不会抛出异常。
⑤ 指定返回类型。
⑥ Lamada 函数体。
根据上图定义一个完整的 lamada 表达式:
1 | auto f = [](int a) noexcept -> int { return a + 1; }; |
二、返回类型
很多时候 lamada 表达式的返回值类型是非常明显的,编译器可以根据return
语句自动推导出返回类型,这个时候我们可以省略表达式的返回值定义:
1 | auto x1 = [](int a) {return a + 1}; // OK: return type is int |
但是,初始化列表不能用于返回值的自动推导:
1 | auto x2 = [](int a) {return {a+1, a+2}; }; // error: 无法推导出返回值类型 |
三、捕获列表
lamada 表达式可以通过捕获列表捕获一定范围内的变量:
[]
不捕获任何变量。[&]
按引用捕获:捕获外部作用域中的所有变量,并作为引用在函数体中使用。[=]
按值捕获:捕获外部作用域中的所有变量,并作为副本在函数体中使用。[=, &foo]
按值捕获外部作用域中的所有变量,并按引用捕获 foo 变量。[bar]
按值捕获 bar 变量,同时不捕获其他变量。[this]
捕获 lamada 所在的当前类中的this
指针,让 lamada 表达式拥有和当前类成员函数同样的访问权限。如果已经使用了&
或=
,就默认添加此选项。捕获 this 的目的是可以在 lamada 中使用当前类的成员函数和成员变量。
四、异常约束
可以使用noexcept
来指定和约束 Lamada 表达内不会抛出异常,如果抛出异常,编译器会产生编译警告。
1 | // throw_lambda_expression.cpp |
五、mutable
正常情况下,按值捕获的变量,其值在 Lamada 表达式内是不能被修改的(遵循const-by-value
),如下面的代码编译会报错:
1 | int n = 1; |
可以使用mutable
关键字改变这种行为:
1 | int n = 1; |
虽然在 Lamada 表达式内可以修改n
的值,但n
仍是按值传递,因此外部n
的值没有被改变。