考虑example from this page,转载如下
struct S {
static const int c;
};
const int d = 10 * S::c; // not a constant expression: S::c has no preceding
// initializer, this initialization happens after const
const int S::c = 5; // constant initialization, guaranteed to happen first
为什么d
的初始化不是常量表达式(因此不是常量初始化过程的一部分)?注释似乎是因为它使用的值没有前面的初始值设定项,但似乎没有在将表达式限定为常量表达式的条件列表中提及(列出的条件为{{ 3}})。特别是哪些条件限定某些东西是一个常量表达式,它是否违反了?
如果它与必须在编译时评估常量初始化这一事实有关,那么标准提到恒定初始化不需要在编译时发生,甚至可能发生在例如加载时间。那么为什么不在编译时初始化c
而在加载时只是d
? (我可能会在这里考虑自己)
here我能够找到一个类似的问题Thanks to Jayesh,但答案似乎是关于左值转换的左值,这里左值转换的左值是多少?除此之外,标准中没有引用关于这里违反了哪些条件。答案也没有解释为什么初始化不会分解为加载时和编译时。
答案 0 :(得分:4)
根据标准§6.6.2/ p2静态初始化[basic.start.static] :
如果是变量或临时对象,则执行常量初始化 静态或线程存储持续时间由常量初始化 实体的初始化程序。
现在,在d
初始化时,编译器发现c
尚未静态初始化(即尚未定义)。因此,d
的初始值设定项不符合常量表达式,因此d
的初始化符合动态初始化条件。由于静态初始化在动态初始化之前发生,c
将在d
之前初始化,因此在d
时。初始化c
已初始化,因此代码有资格。
现在,如果您更改初始化顺序或初始化c
内联,d
的初始化程序有资格作为常量表达式,因为编译器在d
初始化时已经看到了c
的静态初始化(即c
的定义)。
现在,关于为什么在第一种情况下d
的初始化器不是常量表达式的答案由§8.20/ p2给出常量表达式[expr.const] (强调矿):
2 表达式e是核心常量表达式,除非 评估e,遵循抽象机的规则(4.6), 将评估以下表达式之一:
...
2.7 - 左值 - 右值转换(7.1),除非它适用于
2.7.1 - 整数或枚举类型的非易失性glvalue,它将引用到具有前面初始化的完整非易失性const对象,用常量初始化表达
在表达式10 * c中,c没有先前的初始化,因此不是常量表达式。