【问题标题】:Can constexpr be combined with volatile?constexpr 可以和 volatile 结合使用吗?
【发布时间】:2015-05-07 03:45:09
【问题描述】:

以下 sn-p 在 Clang 3.5 中可以正常工作,但在 GCC 4.9.2 中不能:

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

有错误:

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

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

movl    $5, -4(%rsp)

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

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

【问题讨论】:

  • constexprconst 不一样
  • @TheBuzzSaw:volatile 并不意味着任何事情都有改变的趋势。它只是意味着内存访问可能会产生副作用,因此编译器应将其视为 I/O。即使值保证保持不变,也很有必要在系统上使用volatile
  • @user4637702 是的,但其他方式不正确。例如,尝试创建一个constexpr std::string 对象。
  • @TheBuzzSaw 如您所描述的那样使用布尔值是未定义的行为。
  • @TheBuzzSaw 例如,const volatile 可能适用于另一个进程同时修改的文件的只读内存映射,或硬件设备的只读内存映射寄存器。跨度>

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


【解决方案1】:

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

目前的措辞中似乎没有语言说明 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

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

左值到右值的转换 (4.1),除非它应用于

所有例外都需要:

[...]指的是非易失性 [...] 对象 [...]

【讨论】:

  • 知道必须有 DR,但找不到。干得好。
【解决方案2】:

引用 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 的表达式不能是 core-constant-expression,因为它将左值到右值的转换应用于 volatile 类型的左值([expr.const]/ 2)。因此,计算i 的表达式既不是整型常量表达式也不是常量表达式。我不确定该声明中的constexpr 除了使i 隐含地const 和(向@T.C. 点头)要求其初始化程序是一个常量表达式之外还有什么作用。

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

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

【讨论】:

  • (10.5.3) 中“非易失性”的存在告诉我,该标准至少有可能在某种程度上排除了一般的 volatile 限定类型,而允许这样做是一种疏忽.
  • “我不确定该声明中的 constexpr 除了使 i 隐式为 const 之外还有什么作用。” - 它仍然将初始化器限制为常量表达式。
  • 对于它的价值,这是引入此错误的patch。对 wandbox 的测试显示该错误是在 4.5.4 和 4.6.4 之间引入的。
  • @T.C.事实上,这是委员会在我的回答中提到的缺陷报告中使用的理由。我知道必须为此提供缺陷报告。
  • @user4637702 更改是允许constconstexpr 一起使用。 Revision 166013 介绍了各种constexpr 检查,包括constexprvolatile 一起使用时的错误。
猜你喜欢
  • 2022-11-21
  • 2011-07-12
  • 1970-01-01
  • 2020-03-16
  • 2012-12-25
  • 2013-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多