为什么使用后面定义的另一个常量变量将表达式限定为非常量表达式

时间:2017-06-30 06:35:09

标签: c++ c++14 language-lawyer c++17

考虑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,但答案似乎是关于左值转换的左值,这里左值转换的左值是多少?除此之外,标准中没有引用关于这里违反了哪些条件。答案也没有解释为什么初始化不会分解为加载时和编译时。

1 个答案:

答案 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没有先前的初始化,因此不是常量表达式。

相关问题