使用 lambda 捕获的 constexpr 值作为数组维度

Posted

技术标签:

【中文标题】使用 lambda 捕获的 constexpr 值作为数组维度【英文标题】:Using lambda captured constexpr value as an array dimension 【发布时间】:2015-04-30 01:33:40 【问题描述】:

GCCClang 编译以下代码:

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]; ;

哪个 sn-p 实际上以正确的方式做这件事? C++ 标准是怎么说的?

此问题与Lambda capturing constexpr object有关

【问题讨论】:

VS2015是否接受[&] int Dim[Size]; @dyo:不,error C2057: expected constant expression. Size不是static时VS2015是否接受[] int Dim[Size]; @dyp:当然不是,error C3493: 'Size' cannot be implicitly captured because no default capture mode has been specified 不接受并不明显:clang++可以。 【参考方案1】:

C++11 [expr.prim.lambda]/12

如果 lambda-expression odr-使用 this 或从其到达范围内具有自动存储持续时间的变量,则该实体应由 lambda-expression 捕获。

和/17

每个 id-expression 是对通过副本捕获的实体的 odr-use 都转换为对闭包类型的相应未命名数据成员的访问。 [ 注意: 一个不是 odr-use 的 id-expression 指原始实体,从不指闭包类型的成员。 [...] — 尾注 ]

所以我们甚至不需要在第一个示例中捕获Size(它不是static),因为从该变量读取不是odr-use,因为它可以出现在常量表达式中并且立即对其应用左值到右值的转换,[basic.def.odr]/2

名称显示为潜在求值表达式的变量是 odr-used 除非它是一个满足出现在常量表达式和左值到右值的要求的对象 立即应用转换。

(不过,我不清楚数组边界是否需要 l-t-r 转换。)

同样适用于通过引用捕获Size,或显式(通过复制)捕获Size但不使用它:使用id-expression Size lambda 访问在 Test 中声明的 constexpr 变量,而不是任何捕获的成员(对于按复制捕获:IFF 访问不构成 odr 使用)。

C++14 [expr.prim.lamda]/12 为这里无关的多态 lambda 添加了一些措辞,并将 /17 移动到 /18。 odr-use 的规则更复杂,但我认为这不是 odr-use 出于相同的根本原因(读取编译时常量)。

【讨论】:

长话短说。 VS 2015 有 bug 吗? @SergeyK。大概吧。我会尝试查找最近的规则(C++14 和后 C++14),这可能会有点不同。但我无法想象他们在这里会更加严格。

以上是关于使用 lambda 捕获的 constexpr 值作为数组维度的主要内容,如果未能解决你的问题,请参考以下文章

未捕获 constexpr 变量

我可以将 C++17 无捕获 lambda constexpr 转换运算符的结果用作函数指针模板非类型参数吗?

逗号运算符使lambda表达式非constexpr

Visual Studio 2015 在 constexpr 中使用 lambda

constexpr lambda / ‘x’ 没有命名类型;你的意思是“x”吗?

if constexpr 在模板化 lambda 中未丢弃的错误分支