constexpr 可以和 volatile 结合使用吗?

Can constexpr be combined with volatile?

以下代码片段在 Clang 3.5 中运行良好,但在 GCC 4.9.2 中运行不正常:

int main()
{
    constexpr volatile int i = 5;
}

错误:

error: both 'volatile' and 'constexpr' cannot be used here

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

movl    , -4(%rsp)

在 GCC 中,constexpr int i = 5 被优化掉了,但是 volatile int i = 5 也在汇编中显示了 5volatile const int i = 5 在两个编译器中编译。一个东西同时是 volatile 和 const 并不是一个陌生的概念。

哪个编译器符合标准?

引用 N4140 [dcl.constexpr]/9:

A constexpr specifier used in an object declaration declares the object as const. Such an object shall have literal type and shall be initialized.

文字类型定义在[basic.types]/10:

A type is a literal type if it is:

(10.1) — void; or

(10.2) — a scalar type; or

(10.3) — a reference type; or

(10.4) — an array of literal type; or

(10.5) — a class type (Clause 9) that has all of the following properties:

(10.5.1) — it has a trivial destructor,

(10.5.2) — it is an aggregate type (8.5.1) or has at least one constexpr constructor or constructor template that is not a copy or move constructor, and

(10.5.3) — all of its non-static data members and base classes are of non-volatile literal types.

标量类型在第 9 段中:

Arithmetic types (3.9.1), enumeration types, pointer types, pointer to member types (3.9.2), std::nullptr_t, and cv-qualified versions of these types (3.9.3) are collectively called scalar types.

int 是算术,所以 volatile int 是标量类型,因此是文字类型。 constexpr volatile int i = 5; 因此是一个格式正确的声明。

有趣的是,计算 i 的表达式不能是 core-constant-expression,因为它将左值到右值转换应用于 volatile 类型的左值([expr.const]/2)。因此,计算 i 的表达式既不是 整数常量表达式 也不是 常量表达式 。我不确定该声明中的 constexpr 除了使 i 隐式 const 和(向 点头)要求其初始值设定项为常量表达式之外还有什么影响.

我已将此报告为 GCC bug 65327,我们将看看 GCC 的人怎么说。

2015-03-16 更新:修复了 GCC 5 的错误。

是的,这是有效的,为此提交了 defect report 1688: Volatile constexpr variables ,说:

There does not appear to be language in the current wording stating that constexpr cannot be applied to a variable of volatile-qualified type. Also, the wording in 5.19 [expr.const] paragraph 2 referring to “a non-volatile object defined with constexpr” might lead one to infer that the combination is permitted but that such a variable cannot appear in a constant expression. What is the intent?

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

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

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

constexpr volatile int i = 5;    
constexpr int y = i ;         // Not valid since i is volatile

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

an lvalue-to-rvalue conversion (4.1) unless it is applied to

所有例外要求:

[...]that refers to a non-volatile [...] object [...]