首先摆出Lambda表达式语法
lambda-expression:
lambda-introducer lambda-declaratoropt compound-statement
lambda-introducer:
[ lambda-captureopt ]
lambda-capture:
capture-default
capture-list
capture-default , capture-list
capture-default:
&
=
capture-list:
capture
capture-list , capture
capture:
identifier
& identifier
this
lambda-declarator:
( parameter-declaration-clause ) attribute-specifieropt mutableopt exception-specificationopt trailing-return-typeopt
然后用一张图表示他们的属性:
-
capture 子句)
-
参数列表)
-
可变规范)
-
异常规范)
-
返回类型)
-
lambda 体)
之后是capture 子句(最让人搞不懂的地方)
&) 前缀的变量通过引用访问,没有该前缀的变量通过值访问。通过只访问局部变量是只读的。除非你加上了mutable。。
[ ] 指示 lambda 表达式的主体不访问封闭范围中的变量。
factor,则以下 capture 子句等效:
[&total, factor] [factor, &total] [&, factor] [factor, &] [=, &total] [&total, =]
capture-default 时,只有 lambda 中提及的变量才会被捕获。
以下代码片段给出了一些示例。
struct S { void f(int i); };
void S::f(int i) {
[&, i]{}; // OK
[&, &i]{}; // ERROR: i preceded by & when & is the default
[=, this]{}; // ERROR: this when = is the default
[i, i]{}; // ERROR: i repeated
}
可变参数模板示例中所示:
template<class... Args>
void f(Args... args) {
auto x = [args...] { return g(args...); };
x();
}
在使用 capture 子句时,建议记住以下几点(尤其是使用采取多线程的 lambda 时):
-
mutable 允许修改副本,而不能修改原始项。美柚mutable连副本都不能修改)
-
引用捕获会反映外部变量的更新,而值捕获却不会反映。
-
引用捕获引入生存期依赖项,而值捕获却没有生存期依赖项。
参数列表
lambda declarator)是可选的,它类似于函数的参数列表。
mutable 的情况下,可以省略空括号。(也就是后面直接接lambda体的)如
[&] {int a, b = 1;a = b + 1; }();
可变规范
mutable。
异常规范
throw() 异常规范且 lambda 体引发异常将编译错误
返回类型
->。
下面的代码示例片段说明了这一原则。
auto x1 = [](int i){ return i; }; // OK: return type is int auto x2 = []{ return{ 1, 2 }; }; // ERROR: return type is void, deducing // return type from braced-init-list is not valid auto x2 = [](int i) -> initializer_list<int>{return {1, 2};}; //OK: return type is compatible
Lambda 体
普通函数和 lambda 表达式的主体均可访问以下变量类型:
-
参数
-
本地声明变量
-
this 时)
-
具有静态存储持续时间的任何变量(例如,全局变量)
lambda 表达式的主体使用默认捕获模式来访问隐式捕获的变量。
m 的 lambda 表达式: