C++之lambda表达式

时间:2021-01-23 19:11:24

lambda表达式的语法归纳如下:

C++之lambda表达式

  1. capture子句(在 C++ 规范中也称为 lambda 引导)
  2. 参数列表(可选)
  3. 可变规范(可选)
  4. 异常规范(可选)
  5. 尾随返回类型(可选)
  6. lambda函数体

capture子句

capture子句指定要捕获的变量以及是通过值还是引用进行捕获。有与号&前缀的变量通过引用访问,没有该前缀的变量通过值访问。空capture子句[]指示 lambda 表达式的主体不访问封闭范围中的变量。

可以使用默认捕获模式来指示如何捕获lambda中引用的任何外部变量:[&]表示通过引用捕获引用的所有变量,而[=]表示通过值捕获它们。另外,可以使用默认捕获模式,然后为特定变量显式指定相反的模式。

[a,&b]   // a变量以值的方式呗捕获,b以引用的方式被捕获
[this] // 以值的方式捕获this指针
[&] // 以引用的方式捕获所有的外部自动变量
[=] // 以值的方式捕获所有的外部自动变量
[] // 不捕获外部的任何变量
[=,&a] // 按值捕获外部作用域中所有变量,并按引用捕获a变量。

参数列表

除了捕获变量,lambda还可接受输入参数。参数列表是可选的,它在大多数方面类似于函数的参数列表。

int y = [] (int first, int second) {
return first + second;
};

可变规范

通常,lambda的函数调用运算符为const-by-value,但对mutable关键字的使用可将其取消。它不会生成可变的数据成员。利用可变规范,lambda表达式的主体可以修改通过值捕获的变量。

#include <iostream>
using namespace std;

int main() {
int m = 0;
int n = 0;
[&, n] (int a) mutable { m = ++n + a; }(4);
cout << m << " " << n << endl;
}

运行结果:

5 0

由于变量n是通过值捕获的,因此在调用lambda表达式后,变量的值仍保持0不变。mutable规范允许在lambda中修改n

异常规范

可以使用throw()异常规范来指示lambda表达式不会引发任何异常。

#include <iostream>
using namespace std;

int main() {
[]() {
try {
throw 5;
} catch (int ex){
cout<<ex<<endl;
}
}();

try {
[]() throw(int) {
throw 5;
}();
} catch (int ex){
cout<<ex<<endl;
}
}

返回类型

如果lambda体仅包含一个返回语句或其表达式不返回值,则可以省略lambda表达式的返回类型部分。如果lambda体包含单个返回语句,编译器将从返回表达式的类型推导返回类型。否则,编译器会将返回类型推导为void。需要注意的是,初始化列表不能用于返回值的自动推导。

auto x1 = [](int i){ return i; };  // 正确
auto x2 = []{ return {1, 2}; }; // 错误

lambda函数体

lambda表达式的lambda体可包含普通方法或函数的主体可包含的任何内容。例如,可以直接访问保存在全局数据区的变量,而不需要通过capture子句。

void fillVector(vector<int>& v) {
static int nextValue = 1;
generate(v.begin(), v.end(), [] { return nextValue++; });
}

参考链接

C++ 中的 Lambda 表达式
C++11 学习笔记 lambda表达式
C++11 lambda 表达式解析