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

时间:2018-08-09 04:49:53

标签: c++ c++11 lambda argument-deduction

我早些时候看到了这段代码的等效内容,得知它按预期工作时,我感到有些惊讶:

#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])才能起作用。

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

1 个答案:

答案 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都会隐式捕获隐式捕获的实体。