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

这个问题已经在这里有了答案:

  • 为什么有时不需要在lambda中捕获const变量? 3个答案

这样编译:

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个解决方案
38 votes

Lambda的作用域可以隐式捕获其作用域内的变量。

您的变量在到达范围内,因为它们在定义lambda的(主)函数中是局部变量。

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

具有关联的Capture-default的lambda表达式不具有 明确捕获具有自动存储期限的此变量或变量 [..],据说 如果该实体隐式捕获实体(即此实体或变量) 复合陈述:

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

-在可能进行评估的表达式([basic.def.odr])中命名实体,其中包含的完整表达式取决于 在以下范围内声明的通用lambda参数: lambda表达式。

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

条件表达式const int是核心常量表达式,除非 29.6951313609851905的评估,[..]将评估以下表达式之一:

左值到右值转换([conv.lval]),除非将其应用于:

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

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

此外[expr.const] 1826提到:

用常量初始化的const整数可以在常量表达式中使用,但是用常量初始化的const浮点变量不能使用。

在为什么为什么有时不需要在lambda中捕获const变量中的更多内容?

gsamaras answered 2020-07-22T00:15:35Z
9 votes

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

具有关联的Capture-default的lambda表达式不具有 明确捕获具有自动存储期限的此变量或变量 (这不包括发现的任何ID表达式都引用了 据说是init-capture的关联非静态数据成员) 如果该实体隐式捕获实体(即此实体或变量) 复合陈述:

odr-使用(3.2)实体,或

以可能评估的表达式(3.2)命名实体,其中 包含全表达式取决于泛型lambda参数 在lambda表达式的可达范围内声明。

另外,.open-std.org:

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

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

msc answered 2020-07-22T00:16:22Z
translate from https://stackoverflow.com:/questions/46724260/why-are-const-ints-or-shorts-captured-implicitly-in-lambdas