为什么常量(或空头)在lambdas中被隐式捕获
Why are const ints (or shorts) captured implicitly in lambdas?
编译:
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的不同版本)上都测试过它。它在所有情况下都表现相同。
Lambda的作用域可以隐式捕获其作用域内的变量。
您的变量处于到达范围内,因为它们是定义lambda的(main)函数的本地变量。
然而,有一些标准可以通过这种机制捕获变量,如[expr.prim.lambda]/12:中所述
具有关联捕获默认值的lambda表达式显式捕获此或具有自动存储持续时间的变量[..],据说如果复合语句:
-odr使用(〔basic.def.odr〕)实体或
-在可能求值的表达式([basic.def.odr])中命名实体,其中封闭的完整表达式依赖于在lambda表达式。
最重要的部分在[expr.const]/2.7:中
条件表达式
e
是核心常量表达式,除非e
,[..]的评估将评估以下表达式之一:左值到右值的转换([conv.val]),除非它应用于:
integral或枚举类型的非易失性glvalue,其引用具有先前初始化的非易失性常量对象,使用常量表达式初始化。
所以const int
是核心常量表达式,而const float
不是。
此外,〔expr.const〕1826提到:
用常量初始化的const整数可以在常量表达式中使用,但用常数初始化的常量浮点变量不能。
请参阅为什么有时不需要在lambda中捕获常量变量?
C++14草案N4140 5.1.2.12[expr.prim.lambda]:
具有关联捕获默认值的lambda表达式显式捕获此变量或具有自动存储持续时间的变量(这排除了已发现引用init捕获的关联非静态数据成员)如果复合语句:
odr使用(3.2)实体或
在可能求值的表达式(3.2)中命名实体,其中封闭的完整表达式依赖于泛型lambda参数在lambda表达式的到达范围内声明。
此外,.open-std.org/
用常量初始化的常量整数可以在常量中使用表达式,但使用常量不能。这是有意的,是为了与C++03兼容同时鼓励一致使用constexpr。有些人然而,我发现这种区别令人惊讶。
还观察到,允许常量浮点变量为常量表达式将是打破ABI的变化,因为它影响lambda捕获
- #定义c-预处理器常量..我做错了什么
- 用C++中的一个变量定义一个常量
- 什么时候在C++中返回常量引用是个好主意
- 代理对象的常量正确性
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 通过多个头文件使用常量变量
- 在cuda线程之间共享大量常量数据
- 不能在初始值设定项列表中将非常量表达式从类型 'int' 缩小到'unsigned long long'
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 是默认情况下分配给char数组常量的值
- 私有类型的静态常量成员
- 类似枚举的计算常量
- 递归模板化函数不能分配给具有常量限定类型"const tt &"的变量"state"
- 为什么我可以通过引用修改常量返回
- 如何创建长度由常量参数指定的数组
- 当一个值是非常量但用常量表达式初始化时使用constexpr
- 返回常量对象引用 (getter) 和仅返回字符串有什么区别?
- 隐式常量/非常量运算符布尔
- 非常量变量只读位置的赋值
- 为什么常量(或空头)在lambdas中被隐式捕获