constexpr可以与volatile结合使用吗?

时间:2015-03-05 17:02:29

标签: c++ c++11 gcc clang language-lawyer

以下代码段在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也在程序集中显示5volatile const int i = 5在两个编译器中编译。对于同时具有易变性和常量的东西而言,这不是一个外国概念。

标准中哪种编译器是正确的?

2 个答案:

答案 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修复了错误。