GCC
和Clang
会编译以下代码:
void Test()
{
constexpr int Size = 3;
auto Lambda = [Size]{ int Dim[Size]; };
}
但是,VisualStudio 2015 CTP 6
没有。尽管如此,所有3个编译器都对此代码感到满意:
void Test()
{
static constexpr int Size = 3;
auto Lambda = []{ int Dim[Size]; };
}
哪个片段实际上是以正确的方式进行的? C ++标准说什么?
有关答案 0 :(得分:6)
C ++ 11 [expr.prim.lambda] / 12
如果lambda表达式odr-使用此变量或具有自其存储持续时间的变量,则该实体应由lambda表达式捕获。
和/ 17
每个 id-expression 是由副本捕获的实体的odr使用,它被转换为对闭包类型的相应未命名数据成员的访问。 [注意: id-expression 不是odr-use 指原始实体,永远不是封闭类型的成员。 [...] - 结束记录]
所以我们甚至不需要在第一个例子(它不是Size
)中捕获static
,因为从该变量读取并不是一种使用,因为它可能出现在常量表达式和左值到右值的转换立即应用于它,[basic.def.odr] / 2
其名称显示为可能已评估的表达式的变量是odr-used,除非它是满足出现在常量表达式和左值到右值的要求的对象 立即转换。
(但我不清楚阵列边界是否需要进行l-t-r转换。)
通过引用捕获Size
或显式捕获Size
(通过复制)但不使用odr时,同样适用:使用 id-expression lambda中的Size
访问constexpr
中声明的Test
变量,而不是任何捕获的成员(对于copy-by-copy:IFF,访问不构成使用odr)。
C ++ 14 [expr.prim.lamda] / 12为这里不相关的多态lambda添加了一些措辞,并将/ 17移动到/ 18。使用odr的规则更复杂,但我认为这不是因为相同的潜在原因(读取编译时常量)而使用的。 -