C++14 中的§5.19/3 定义了一个整型常量表达式和一个转换后的常量表达式:
An integral constant expression is an expression of integral or unscoped enumeration type, implicitly converted to a prvalue, where the converted expression is a core constant expression. [ Note: Such expressions may be used as array bounds (8.3.4, 5.3.4), as bit-field lengths (9.6), as enumerator initializers if the underlying type is not fixed (7.2), and as alignments (7.6.2). —end note ] A converted constant expression of type
Tis an expression, implicitly converted to a prvalue of typeT, where the converted expression is a core constant expression and the implicit conversion sequence contains only user-defined conversions, lvalue-to-rvalue conversions (4.1), integral promotions (4.5), and integral conversions (4.7) other than narrowing conversions (8.5.4). [ Note: such expressions may be used innewexpressions (5.3.4), ascaseexpressions (6.4.2), as enumerator initializers if the underlying type is fixed (7.2), as array bounds (8.3.4), and as integral or enumeration non-type template arguments (14.3). —end note ]
也许我遗漏了什么,但我的第一印象是每个整型常量表达式都是一个转换后的常量表达式。
编辑
而且我也认为这一段有错误:
代替:
转换后的 T 类型常量表达式是一个表达式,隐式转换为 T 类型的纯右值,...
应该是:
转换后的 T 类型常量表达式是一个表达式,隐式转换为整数类型的纯右值,...
并且这个改变允许编译以下代码:
#include <iostream>
struct A { operator int() { return 5; } } a;
int main() {
int b[a]{ 0, 1, 2, 3, 4 };
std::cout << b[4] << '\n';
}
其中 a 在声明 int b[a]{ 0, 1, 2, 3, 4}; 是一个转换后的常量表达式 类型为 A,隐式转换为整数类型 (int) 的纯右值,其中转换后的表达式 5 是 核心常量表达式,隐式转换序列只包含用户定义的转换。
最佳答案
这两个定义都是必需的,因为有些事情你可以用一个做,但不能用另一个做。不,不是每个整型常量表达式都是真正的转换常量表达式。对于明显的示例,已转换的常量表达式 禁止缩小转换,但整型常量表达式 不会。
因此我不能这样做:
enum x : char { a = 1024 };
如果枚举的初始值设定项允许整型常量表达式,而不是转换后的常量表达式,那么这正是允许的。
作为维恩图,我将情况画成这样:
因此,两者之间有相当多的重叠(可能比此图所暗示的更多),但每个都允许至少一些其他不允许的事情。我已经给出了每个方向的一个项目的示例,但没有尝试详尽地列出差异。
我并不完全相信用户定义的转换被禁止用于整型常量表达式(并且快速测试表明我目前使用的编译器允许它们)。这将给出我最初写这个答案的情况,更像是这样:
关于c++ - 为什么我们需要两个定义: integral constant expression and converted constant expression?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34360286/