根据缺陷报告1688,C标准允许constexpr volatile
变量,该问题已于2013年9月解决:
这种组合是有意允许的,在某些情况下可用于强制常量初始化。
它看起来只允许constinit volatile
,这在C20之前是不可用的。
在某些情况下,当前的编译器在处理constexpr volatile
时仍然存在分歧。例如,下面的程序用一个变量初始化另一个变量:
int main() {
constexpr volatile int i = 0;
constexpr volatile int j = i;
return j;
}
愚者和MSVC都接受,但Clang抱怨:
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;
在线演示:https://gcc.godbolt.org/z/43ee65Peq
这里是哪种编译器?为什么?
2条答案
按热度按时间b09cbbtk1#
Clang是正确的。从
i
初始化j
需要在i
上执行左值到右值的转换,但根据[expr.const]/5.9,在常量表达式中不允许在volatile
glvalue上执行左值到右值的转换。由于i
是constexpr
变量,因此必须由常量表达式初始化它。我不知道为什么愚者和MSVC选择不执行这一规则,除了所有的C++编译器总是人手不足,不能实现他们期望的一切。
8cdiaqws2#
您链接的缺陷报告显示它不应该工作,因此Clang正确。
(...)允许“使用constexpr定义的非易失性对象”(...),但此类变量不能出现在常量表达式中。其意图是什么?
但更有趣的是:为什么Clang关心而其他编译器不关心呢?
在我看来,这是因为JF Bastien,一个在Clang / LLVM世界里非常有影响力的人物,他个人不喜欢
volatile
:)他已经proposing to remove它从语言很长一段时间。所以如果它被允许禁止volatile某处,他可能不遗余力地使它如此。如果没有其他原因,只是为了防止人们写的代码,将不得不重写,如果他的建议最终被接受。
如果你想知道他的推理,他还在CppCon上做了一个关于他的deprecation proposal的演讲。