为什么在lambdas中隐式捕获const int(或short)?

时间:2017-10-13 07:03:24

标签: c++ lambda scope language-lawyer one-definition-rule

编译:

int main() {
    const int x = 123;
    auto g = []() { std::cout << x << "\n"; };
    g();
}

但是这个:

int main(){
    const float x = 123;
    auto g = []() { std::cout << x << "\n"; };
    g();
}

产生

  

“错误:未捕获'x'”

为什么?

我在GCC(各种版本从5.0.0到8.0.0)和Clang(各种版本从4.0.0到6.0.0)上测试过它。它在所有情况下都表现相同。

2 个答案:

答案 0 :(得分:38)

Lambda的范围可以在其到达范围内隐式捕获变量。

您的变量在范围内,因为它们是定义lambda的(主)函数的本地变量。

但是,有一些标准可以通过这种机制捕获变量,如[expr.prim.lambda]/12中所述:

  

具有相关捕获默认值的lambda表达式   使用自动存储持续时间明确捕获此变量或变量   [...],据说   隐含地捕获实体(即,这个或变量)   化合物语句:

     

-odr-uses([basic.def.odr])实体,或

     

- 在潜在评估表达式([basic.def.odr])中命名实体,其中封闭的full-expression依赖于   在...的到达范围内声明的泛型 lambda参数   λ-表达

最重要的部分是[expr.const]/2.7

  

条件表达式e核心常量表达式,除非   评估e,[..]将评估以下表达式之一:

     

左值到右值的转换([conv.lval]),除非它适用于:

     

整数或枚举类型的非易失性glvalue,它引用具有先前初始化的非易失性const对象,   用常量表达式初始化。

因此const int核心常量表达式,而const float则不是。

此外[expr.const]1826提及:

  

用常量初始化的const整数可用于常量表达式,但用常量初始化的const浮点变量不能

Why is a const variable sometimes not required to be captured in a lambda?

中了解详情

答案 1 :(得分:9)

C ++ 14 draft N4140 5.1.2.12 [expr.prim.lambda]:

  

具有相关捕获默认值的lambda表达式   使用自动存储持续时间明确捕获此变量或变量   (这排除了任何被发现引用的id表达式   据说是init-capture的相关非静态数据成员   隐含地捕获实体(即,这个或变量)   化合物语句:

     

odr-uses(3.2)实体

     

在可能评估的表达式(3.2)中命名实体   封闭full-expression取决于通用lambda参数   在lambda表达式的范围内声明。

另外,.open-std.org

  

用常量初始化的const整数可用于常量   表达式,但用a初始化的const浮点变量   常数不能。这是故意的,与C ++ 03兼容   同时鼓励一致使用constexpr。有些人有   然而,发现这种区别是令人惊讶的。

     

还观察到允许const浮点变量为   常数表达式将是ABI突破性的变化,因为它会   影响lambda捕获。