自动参数捕获的推导规则是什么?

What are the deduction rules for automatic argument capture?

我之前看到了这段代码的等价物,得知它按预期工作时我有点惊讶:

#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]),它才能工作。

自动参数捕获的推导规则是什么?

这在[expr.prim.lambda.capture]p7中有描述:

For the purposes of lambda capture, an expression potentially references local entities as follows:

  • An id-expression that names a local entity potentially references that entity; an id-expression that names one or more non-static class members and does not form a pointer to member ([expr.unary.op]) potentially references *this.

  • A this expression potentially references *this.

  • A lambda-expression potentially references the local entities named by its simple-captures.

If an expression potentially references a local entity within a declarative region in which it is odr-usable, and the expression would be potentially evaluated if the effect of any enclosing typeid expressions ([expr.typeid]) were ignored, the entity is said to be implicitly captured by each intervening lambda-expression with an associated capture-default that does not explicitly capture it.

换句话说:

如果使用需要定义,lambda 在以下情况下会隐式捕获,typeid 表达式将被忽略,并且不会显式捕获它们:

  • 一个变量被命名;或者如果出现非静态 class 成员的名称(不计算指向成员的指针),则 *this 被隐式捕获,或者

  • this出现,然后*this被隐式捕获

隐式捕获的实体由每个具有默认捕获的中间 lambda 隐式捕获。