【问题标题】:Why does this using another constant variable defined later qualify an expression as a non constant expression为什么使用稍后定义的另一个常量变量将表达式限定为非常量表达式
【发布时间】:2017-06-30 06:35:09
【问题描述】:

考虑到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 的初始化不是常量表达式(因此不是常量初始化过程的一部分)?评论似乎说这是因为它使用了一个没有前面的初始化程序的值,但是在将表达式限定为常量表达式的条件列表中似乎没有提到(条件列在@987654322 @)。特别是它违反了哪个条件使某事物成为常量表达式?

如果它与必须在编译时评估常量初始化的事实有关,那么标准提到常量初始化不需要在编译时发生,甚至可以在例如加载时发生。那么为什么不在编译时初始化 c 而在加载时初始化 d 呢? (我可能会认为自己在这里陷入了一个圈子)


Thanks to Jayesh我能找到一个类似的问题"surprising" constant initialization because of definition order,但答案似乎是关于左值到右值的转换,这里的左值到右值的转换在哪里?除此之外,这里没有引用标准中的哪些条件被违反。答案也没有解释为什么初始化没有在加载时和编译时分开。

【问题讨论】:

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


【解决方案1】:

根据标准§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— 整数或枚举类型的非易失性左值,它引用 具有前面初始化的完整非易失性 const 对象,用常量初始化表达。

在表达式 10 * c 中,c 没有前面的初始化,因此不是常量表达式。

【讨论】:

  • “引用类型”
  • 相关项目符号是 2.7。 (一旦看到S::c 的初始化,2.7.1 就适用。)
猜你喜欢
  • 1970-01-01
  • 2016-03-25
  • 2019-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-27
  • 2014-08-26
  • 1970-01-01
相关资源
最近更新 更多