Can one volatile constexpr variable initialize another one in C++?

Fed*_*dor 27 c++ volatile language-lawyer constexpr

C++ standard allows constexpr volatile variables per defect report 1688, which was resolved in September 2013:

The combination is intentionally permitted and could be used in some circumstances to force constant initialization.

It looks though that the intention was to allow only constinit volatile, which was not available before C++20.

Still the current compilers diverge in treatment of constexpr volatile in certain circumstances. For example, this program initializes one such variable by the other one:

int main() {
    constexpr volatile int i = 0;
    constexpr volatile int j = i;
    return j;
}
Run Code Online (Sandbox Code Playgroud)

It is accepted in GCC and MSVC, but Clang complains:

error: constexpr variable 'j' must be initialized by a constant expression
    constexpr volatile int j = i;
                           ^   ~
note: read of volatile-qualified type 'const volatile int' is not allowed in a constant expression
    constexpr volatile int j = i;
Run Code Online (Sandbox Code Playgroud)

Online demo: https://gcc.godbolt.org/z/43ee65Peq

Which compiler is right here and why?

Bri*_*ian 17

叮当是正确的。jfrom的初始化i要求对 执行左值到右值的转换i,但根据 [expr.const]/5.9,在volatile常量表达式内决不允许对左值到右值的转换。由于i是一个constexpr变量,因此必须用常量表达式对其进行初始化。

我不知道为什么 GCC 和 MSVC 选择不强制执行这条规则,除了所有 C++ 编译器永远人手不足,无法实现他们期望的一切。


小智 12

您链接的缺陷报告显示它不应该工作,所以 Clang 是正确的。

\n
\n

(...) \xe2\x80\x9ca 允许使用 constexpr\xe2\x80\x9d (...) 定义的非易失性对象,但此类变量不能出现在常量表达式中。意图是什么?

\n
\n

但更有趣的是:为什么 Clang 关心而其他编译器不关心?

\n

在我看来,发生这种情况是因为JF Bastien,一个在 Clang / LLVM 领域非常有影响力的人物,他个人不喜欢volatile:)

\n

长期以来,他一直建议将其从语言中删除。所以如果允许在某个地方禁止 volatility,他可能会不遗余力地做到这一点。如果没有其他原因,只是为了阻止人们编写如果他的提案最终被接受就必须重写的代码。

\n

如果您想了解他的理由,他还在 CppCon 上发表了关于他的弃用提案的演讲。

\n

  • JF Bastien 演讲的要点是,他希望用“易失性负载”和“易失性存储”来**替换**“易失性”作为类型限定符,作为进行易失性访问的方法。对我来说有一定道理。(作为限制这些应用范围的一种方法,仅适用于在 asm 中真正有意义的事物。) (3认同)