constexpr可以与volatile结合使用吗?

use*_*702 26 c++ gcc clang language-lawyer c++11

以下代码段在Clang 3.5中正常工作,但在GCC 4.9.2中没有:

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

有错误:

错误:这里不能使用'volatile'和'constexpr'

如果我检查Clang生成的程序集,它会5按预期显示:

movl    $5, -4(%rsp)
Run Code Online (Sandbox Code Playgroud)

在GCC中,constexpr int i = 5被优化掉了,但volatile int i = 5也在5装配中显示出来.volatile const int i = 5在两个编译器中编译.对于同时具有易失性和常量的东西而言,这不是一个外国概念.

哪个编译器的标准是正确的?

Sha*_*our 24

是的,这是有效的,有缺陷报告1688:为此提交的挥发性constexpr变量,说:

目前的措辞中似乎没有语言表明constexpr不能应用于volatile限定类型的变量.另外,5.19 [expr.const]第2段中的措辞提到"用constexpr定义的非易失性对象"可能导致人们推断该组合是允许的,但这样的变量不能出现在常量表达式中.意图是什么?

它被拒绝为非缺陷(NAD),回应和理由是:

有意允许组合,并且可以在某些情况下使用该组合来强制不断初始化.

正如DR指出的那样,这样的变量本身不能用于常量表达式:

constexpr volatile int i = 5;    
constexpr int y = i ;         // Not valid since i is volatile
Run Code Online (Sandbox Code Playgroud)

Section [expr.const]/2包括使条件表达式不是核心常量表达式的所有情况,包括:

除非适用,否则左值到右值的转换(4.1)

并且所有例外都需要:

[...]指的是非挥发性物品[...]


Cas*_*sey 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)统称为标量类型.

int是算术,因此volatile int是标量类型,因此是文字类型.constexpr volatile int i = 5;因此是一个结构良好的宣言.

有趣的是,求值的表达式i不能是核心常量表达式,因为它将左值到右值的转换应用于volatile类型的glvalue([expr.const]/2).因此,求值的表达式i既不是整型常量表达式也不是常量表达式.我不确定该constexpr声明中的内容是否有任何影响,除了i隐式地const,并且(向@TC点头)要求其初始化器是一个常量表达式.

我已将此报告为GCC错误65327,我们将看到GCC人员所说的话.

2015-03-16更新:已针对GCC 5修复了错误.

  • "我不确定该声明中的constexpr是否有任何影响,除了使我隐式const." - 它仍然将初始化程序限制为常量表达式. (4认同)