第一个代码段编译时没有任何警告(live example):
#include <iostream>
struct A {
constexpr A(): i(5){}
constexpr operator int() { return 5; }
int i;
};
int main() {
A a;
int b[a]{ 0, 1, 2, 3, 4 };
std::cout << b[4] << '\n';
}
现在通过在转换运算符live example中返回i
来更改上述代码段:
constexpr operator int() { return i; }
GCC警告b
是VLA。
对我来说,这两个变体似乎都符合C ++ 14中的段落§5.19[expr.const] / 3。
答案 0 :(得分:17)
您正在i
上执行l-t-r转换,但是对于[expr.const] /(2.7)这里不违反,(2.7.3)必须适用:
(2.7.1)涉及完整的对象,(2.7.2)谈论字符串文字,(2.7.4)是关于生命周期在表达式的评估中开始的对象 - 不适用于a
的声明在b
之前。
将a
定义为constexpr
且代码符合要求。
澄清标准内容的一个小附录:括号内的表达式必须是std::size_t
([dcl.array]/1)类型的转换常量表达式,在[expr.const]/4中定义为< / p>
转换常量表达式
T
是一个表达式,隐式转换为类型T
,其中转换为 表达式是一个常量表达式和[......满足要求...]
因此,实际上,标准是否对
感兴趣constexpr std::size_t s = a;
是有效的。由于上述原因,它不是 - 试图使用先前定义的非constexpr
对象的子对象。
答案 1 :(得分:4)
数组大小必须是编译时常量,但在第二个示例中,A::i
的初始化在运行时之前不会发生。