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

这编译:

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的各种版本)上testing过它。 它在所有情况下performance相同。

Lambda的作用域可以隐式捕获到达范围内的variables。

你的variables在范围之内,因为它们是定义lambda的(main)函数的本地。

但是,如[expr.prim.lambda] / 12中提到的那样,通过这种机制可以捕获variables的某些标准:

一个带有关联捕获默认值的lambdaexpression式,如果没有明确地捕获这个或具有自动存储持续时间[..]的variables,则说隐式地捕获实体 (即,这个或一个variables ),如果复合语句:

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

将实体命名为潜在评估expression式([basic.def.odr]),其中封闭的完整expression式依赖于在lambdaexpression式的范围内声明的通用lambda参数

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

一个条件expression式e是一个核心常量expression式,除非评估e ,[..]将评估下列expression式之一:

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

整数或枚举types的非易失性glvalue,它引用具有前面初始化的非易失性常量对象,用常量expression式进行初始化。

所以const int是一个核心常量expression式,const float不是。

而且[expr.const] 1826提到:

在常量expression式中可以使用用常量初始化的常量整数, 但是用常量初始化的常量浮点variables不能

阅读更多为什么是一个constvariables有时不需要在lambda捕获?

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

具有关联捕获默认值的lambdaexpression式不会显式捕获此variables或具有自动存储持续时间的variables(这不包括任何已发现指向init-capture关联的非静态数据成员的idexpression式)说隐式捕获实体 (即,这个或一个variables),如果复合语句:

odr-uses(3.2)实体 ,或者

将实体命名为潜在评估expression式(3.2),其中封闭的完整expression式依赖于在lambdaexpression式的范围内声明的通用lambda参数。

另外, .open-std.org :

在常量expression式中可以使用用常量初始化的常量整数,但是用常量初始化的常量浮点variables不能。 这是故意的,与C ++ 03兼容,同时鼓励constexpr的一贯使用。 然而有些人发现这个区别令人惊讶。

也有人指出,允许const浮点variables作为常量expression式将是一个ABI突破性的变化,因为它会影响lambda捕获。