为什么在 lambda 中隐式捕获 const int(或 Shorts)? [重复]

问题描述 投票:0回答:2

编译:

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的各个版本)上测试了它。在所有情况下它的行为都是相同的。

c++ lambda scope language-lawyer
2个回答
38
投票

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

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

但是,通过此机制可以捕获变量有一定的标准,如 [expr.prim.lambda]/12:

中所述

具有关联捕获默认值的 lambda 表达式,该表达式不 显式捕获此变量或变量具有自动存储持续时间 [..],据说 隐式捕获实体(即,此或变量),如果 复合语句:

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

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

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

条件表达式

e
是一个核心常量表达式,除非 计算
e
,[..] 将计算以下表达式之一:

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

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

所以

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

此外[expr.const]1826提到:

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

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


9
投票

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

具有关联捕获默认值的 lambda 表达式,该表达式不 显式捕获此变量或具有自动存储持续时间的变量 (这不包括任何已被发现引用的 id 表达式 init-capture 的关联非静态数据成员),据说 隐式捕获实体(即,这个或一个变量),如果 复合语句:

odr-使用(3.2)实体,或

命名潜在评估表达式 (3.2) 中的实体,其中 封闭完整表达式取决于通用 lambda 参数 在 lambda 表达式的到达范围内声明。

另外,.open-std.org

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

还观察到允许 const 浮点变量作为 常量表达式将是一个破坏 ABI 的更改,因为它会 影响 lambda 捕获。

© www.soinside.com 2019 - 2024. All rights reserved.