我早些时候看到了这段代码的等效内容,得知它按预期工作时,我感到有些惊讶:
#include <iostream>
int main()
{
int a = 10;
[=]() mutable {
[&]() {
a += 10;
std::cout << "nested lambda: a=" << a << std::endl;
}(); // call nested lambda
}(); // call first lambda
std::cout << "a=" << a << std::endl;
}
根据需要,输出为
nested lambda: a=20
a=10
令我惊讶的是,编译器发现a
用于嵌套的lambda,并且即使在第一个lambda中未明确使用它,也可以按值正确捕获它。也就是说,编译器必须在嵌套lambda中的a
与外部范围中的a
之间建立连接。我认为参数捕获必须是明确的(即,第一个lambda中的[a]
,嵌套中的[&a]
)才能起作用。
自动参数捕获的推理规则是什么?
答案 0 :(得分:9)
这在[expr.prim.lambda.capture]p7中有描述:
出于lambda捕获的目的,表达式可能会如下引用本地实体:
命名本地实体的 id-expression 可能引用了该实体;一个 id-expression ,它命名一个或多个非静态类成员,并且不构成指向该成员([expr.unary.op])的指针,它们可能引用了
*this
。一个
this
表达式可能引用*this
。一个 lambda-expression 可能引用以其简单捕获命名的本地实体。
如果表达式可能引用了可在其中使用的声明性区域中的本地实体,并且如果任何封闭的
typeid
表达式([expr.typeid])的效果均被满足,则该表达式可能会被评估。被忽略时,该实体被每个介入的 lambda-expression 隐式捕获,而关联的 capture-default 并未明确捕获该实体。
换句话说:
在以下情况下,如果用法需要定义,则lambda会隐式捕获typeid
表达式,并且不会显式捕获它们:
一个变量被命名;或者,如果出现非静态类成员的名称(不计算指向成员的指针),则*this
被隐式捕获,或者
this
出现,然后*this
被隐式捕获
每个默认插入的lambda都会隐式捕获隐式捕获的实体。