constexpr 和未定义的行为

constexpr and undefined behavior

本文关键字:未定义 constexpr      更新时间:2023-10-16

这段代码在GCC 8中编译,但在GCC 7和clang中不编译。

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

这显然是 UB。

我的问题:标准对评估包含 UB 的 constexpr 有什么看法 - 这段代码应该编译吗?

GCC 8 是错误的

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

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

我不会解决你所做的是否是UB(我相信是(,但如果它是UB,那么它不应该编译。

我会看看我是否能找到标准的引文来支持这些断言;但这里不需要棘手的语言律师。 只是一个简单的原则:在编译时计算编译时表达式时,编译器必须审核它为 UB 运行的代码,如果它们遇到 UB(同样,在编译时(,表达式不再是编译时表达式。

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

[expr.const](C++17第2款,目前的C++20第4款草案(:

表达式e核心常量表达式,除非按照抽象机器的规则计算e将计算以下表达式之一:

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

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

"从句 [介绍] 到 [cpp]"也称为核心语言规范。

[expr.const](C++17第5款,目前的C++20第10款草案(:

常量表达式是 glvalue 核心常量表达式,它引用作为常量表达式(定义如下(的允许结果的实体,或者是其值满足以下约束的 prvalue 核心常量表达式:

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

[dcl.constexpr](C++17第9段,目前的C++20草案第10段(:

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

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