C++ Lambda表达式/Lambda 函数/匿名函数
C++11 提供了对匿名函数的支持,称为 Lambda 函数(也叫 Lambda 表达式)。
Lambda 表达式把函数看作对象。Lambda 表达式可以像对象一样使用,比如可以将它们赋给变量和作为参数传递,还可以像函数一样对其求值。
Lambda 表达式本质上与函数声明非常类似。Lambda 表达式具体形式如下:
-
捕获列表。
-
参数列表 (可选)。
-
可变说明 (可选)。
-
异常说明(可选)。
-
返回类型(可选)。
-
表达式主体。
- 捕获列表
捕获列表可以为空。C++变量传递有传值和传引用的区别。可以通过前面的[ ]来指定:
[] // 沒有定义任何变量。使用未定义变量会引发错误。
[x, &y] // x以传值方式传入(默认),y以引用方式传入。
[&] // 任何被使用到的外部变量都隐式地以引用方式加以引用。
[=] // 任何被使用到的外部变量都隐式地以传值方式加以引用。
[&, x] // x显式地以传值方式加以引用。其余变量以引用方式加以引用。
[=, &z] // z显式地以引用方式加以引用。其余变量以传值方式加以引用。
- 参数列表
除了捕获变量之外,lambda还可以接受输入参数。参数列表是可选的,在大多数方面类似于函数的参数列表。在C++14中,如果参数类型是通用的,则可以使用auto关键字作为类型说明符。这告诉编译器将函数调用操作符创建为模板。参数列表中的每个auto实例等同于不同的类型参数。
auto y = [] (auto first, auto second)
{
return first + second;
};
- 可变说明
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 << endl << n << endl;
}
输出为:
5
0
因为变量n
是通过传值捕获的,所以0
在调用lambda表达式之后它的值仍然存在。所述mutable允许n
被lambda表达式修改。
- 异常说明
您可以使用noexcept
来指示lambda表达式不会抛出任何异常。与普通函数一样,如果lambda表达式使用了noexcept
并且lambda抛出了异常,则Visual C ++编译器会生成警告C4297。
- 返回类型
如果lambda主体只包含一个return语句或表达式不返回值,则可以省略lambda表达式的返回类型部分。如果lambda主体包含一个return语句,则编译器会从返回表达式的类型中推断出返回类型。否则,编译器会将返回类型推断为void。请考虑以下示例代码片段,说明此原则。
auto x1 = [](int i){ return i; }; // 正确: 返回类型为 int
auto x2 = []{ return{ 1, 2 }; }; // 错误: 返回类型将为 void
// 大括号初始化列表的返回类型是不合法的
- 表达式主体
与普通函数类似,lambda表达式的主体可以包含函数的主体能包含的任何内容。普通函数和lambda表达式的主体都可以访问这些变量:
- 捕获列表中的变量
- 参数列表中的变量
- 本地声明的变量
- 类的数据成员
- 具有静态存储持续时间的任何变量 - 例如,全局变量