以下代码段在Clang 3.5中正常工作,但在GCC 4.9.2中无法正常工作:
int main()
{
constexpr volatile int i = 5;
}
有错误:
错误:两者都不稳定'和' constexpr'不能在这里使用
如果我检查Clang生成的程序集,它会按预期显示5
:
movl $5, -4(%rsp)
在GCC中,constexpr int i = 5
已被优化,但volatile int i = 5
也在程序集中显示5
。 volatile const int i = 5
在两个编译器中编译。对于同时具有易变性和常量的东西而言,这不是一个外国概念。
标准中哪种编译器是正确的?
答案 0 :(得分:24)
是的,这是有效的,为此提交了defect report 1688: Volatile constexpr variables ,说:
目前的措辞中似乎没有语言 constexpr不能应用于volatile-qualified变量 类型。另外,5.19 [expr.const]第2段中的措辞指的是 “用constexpr定义的非易失性对象”可能导致人们推断 允许组合,但这样的变量不能 出现在一个常量表达式中。意图是什么?
它被拒绝而不是缺陷( NAD ),回应和理由是:
该组合是有意允许的,可以在某些组合中使用 情况迫使不断初始化。
正如DR指出的那样,这个变量本身在常量表达式中不可用:
constexpr volatile int i = 5;
constexpr int y = i ; // Not valid since i is volatile
Section [expr.const] / 2 包括使条件表达式不是核心常量表达式的所有情况,包括:
左值 - 右值转换(4.1),除非它适用于
并且所有例外都需要:
[...]指的是非易失性[...]对象[...]
答案 1 :(得分:17)
引用N4140 [dcl.constexpr] / 9:
对象声明中使用的
constexpr
说明符将对象声明为const
。这样的对象应具有文字类型并应初始化。
文字类型在[basic.types] / 10中定义:
类型是文字类型,如果它是:
(10.1) -
void
;或(10.2) - 标量类型;或
(10.3) - 参考类型;或
(10.4) - 一个文字类型的数组;或
(10.5) - 具有以下所有属性的类类型(第9条):
(10.5.1) - 它有一个简单的析构函数,
(10.5.2) - 它是一个聚合类型(8.5.1)或至少有一个
constexpr
构造函数或构造函数模板,它不是复制或移动构造函数,并且(10.5.3) - 它的所有非静态数据成员和基类都是非易失性文字类型。
标量类型见第9段:
算术类型(3.9.1),枚举类型,指针类型,成员类型指针(3.9.2),
std::nullptr_t
和这些类型的cv限定版本(3.9.3)统称为< em>标量类型。
int
是算术运算,因此volatile int
是标量类型,因此是文字类型。因此,constexpr volatile int i = 5;
是一个结构良好的宣言。
有趣的是,评估i
的表达式不能是核心常量表达式,因为它将左值到右值的转换应用于volatile类型的glvalue([expr.const] ] / 2)。因此,评估i
的表达式既不是整型常量表达式也不是常量表达式。我不确定该声明中的constexpr
除了i
隐式const
之外还有什么影响,并且(向@T.C.点头)要求其初始值设定为常量表达式
我已将此报告为GCC bug 65327,我们会看到海湾合作委员会的人要说的话。
2015-03-16更新:已针对GCC 5修复了错误。