【问题标题】:constexpr and undefined behaviorconstexpr 和未定义的行为
【发布时间】:2019-09-12 15:15:44
【问题描述】:

此代码在 GCC 8 中编译,但在 GCC 7 和 clang 中均不编译。

constexpr int a = 1;
constexpr int b = --const_cast<int&>(a);

这显然是 UB。

我的问题:关于评估包含 UB 的 constexpr,标准语言怎么说 - 这段代码是否应该编译?

【问题讨论】:

  • 为什么这是 UB 对我来说不是很明显?你能引用适用的标准部分吗?
  • @SergeyA 这就是问题所在。 OP 正在询问标准的哪一部分说这是 UB。
  • @FrançoisAndrieux 这不是我的阅读方式。 OP 说:“这显然是 UB。” 对我来说,这不是问题,而是 OP 的声明。
  • @SergeyA 您不能修改 const 对象,但这正是 --const_cast&lt;int&amp;&gt;(a) 所做的。
  • 据我所知constexpr 暗示const,因此您正在修改const 引用,这是未定义的行为。见stackoverflow.com/questions/25209838/…

标签: c++ language-lawyer undefined-behavior constexpr


【解决方案1】:

GCC 8 错误

constexpr 编译时表达式中的所有未定义行为使表达式在编译时不求值(基本上不是 consteval,使用基本上具有该含义的新关键字)。

初始化constexpr 实际上需要consteval 表达式。

如果你做的是 UB(我相信是),我不会说明,但如果是 UB,那么它不应该编译。

我会看看能不能找到标准的引用来支持这些断言;但这里不需要棘手的ing。只是一个简单的原则:在编译时表达式评估期间的编译时,编译器必须审核它为 UB 运行的代码,如果它们运行到 UB(再次,在编译时),则表达式不再是编译时表达式。

【讨论】:

  • 对于它的价值,VC++ 抱怨“错误 C2131:表达式未计算为常量”关于如何初始化 b
  • @pqnet 如果计算表达式,则表达式包含 UB,因此它不是 consteval,您必须使用 consteval 初始化 constexpr。结果程序中没有“UB”,只是一个格式错误的程序。实际上,在编译时,编译器必须为 UB 审核所有内容,并且不能让您在编译时运行 UB。
  • @pqnet 要求constexpr 中没有 UB,所以在这种情况下它被拒绝了。
  • 是的,这段代码格式不正确。有人应该针对 GCC 8 提交错误。
  • @FrançoisAndrieux 如果 C++ 编译器可以证明不能阻止程序的所有执行导致 UB,那么它可以将“输出程序”替换为纸质标志(或其他任何它想要的),包括无法执行的内容(例如打印到控制台的错误消息)。
【解决方案2】:

此代码格式错误,GCC 8 和 9 不正确,无法给出诊断。

[expr.const](C++17 第 2 段,current C++20 draft paragraph 4):

表达式e 是一个核心常量表达式,除非e 的计算遵循抽象机的规则,将计算以下表达式之一:

  • ...

  • 本国际标准的 [intro] 至 [cpp] 条款中规定的具有未定义行为的操作;

  • ...

  • 对象的修改,除非将其应用于文字类型的非易失性左值,该左值引用一个非易失性对象,该对象的生命周期在 e 的评估中开始;

  • ...

“子句 [intro] 到 [cpp]”也称为核心语言规范。

[expr.const](C++17 第 5 段,current C++20 draft paragraph 10):

常量表达式要么是一个泛左值核心常量表达式,它引用一个作为常量表达式(如下定义)的允许结果的实体,要么是一个纯右值核心常量表达式,其值满足以下约束:

“以下约束”仅适用于类类型、数组类型或指针类型的值。

[dcl.constexpr](C++17 第 9 段,current C++20 draft paragraph 10):

在任何constexpr 变量声明中,初始化的完整表达式应为常量表达式。

表达式--const_cast&lt;int&amp;&gt;(a); 不是核心常量表达式,因此不是常量表达式,这既是因为它的求值将具有未定义的行为,而且因为它修改了一个生命周期未在求值中开始的对象。 “shall”语句(除非与“不需要诊断”结合使用)意味着当程序违反它时,实现必须打印诊断消息(例如错误或警告)。

【讨论】:

    猜你喜欢
    • 2011-11-17
    • 1970-01-01
    • 2014-10-23
    • 2013-04-19
    • 2021-11-09
    相关资源
    最近更新 更多