为什么 GCC 以不同方式处理这些片段?
Why are these snippets handled differently by GCC?
第一个片段编译时没有任何警告(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 段。
数组大小必须是编译时常量,但在第二个示例中,A::i
的初始化直到 运行-time 才会发生。
您正在 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), which is defined in [expr.const]/4 as
A converted constant expression of type T
is an expression, implicitly converted to type T
, where the converted
expression is a constant expression and […requirements that are met…]
因此,实际上,标准对
是否感兴趣
constexpr std::size_t s = a;
有效。由于上述原因,它不是 - 尝试使用先前定义的非 constexpr
对象的子对象。
第一个片段编译时没有任何警告(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 段。
数组大小必须是编译时常量,但在第二个示例中,A::i
的初始化直到 运行-time 才会发生。
您正在 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), which is defined in [expr.const]/4 as
A converted constant expression of type
T
is an expression, implicitly converted to typeT
, where the converted expression is a constant expression and […requirements that are met…]
因此,实际上,标准对
是否感兴趣constexpr std::size_t s = a;
有效。由于上述原因,它不是 - 尝试使用先前定义的非 constexpr
对象的子对象。