【问题标题】:Why does a consteval function allow undefined behavior?为什么 consteval 函数允许未定义的行为?
【发布时间】:2020-02-15 16:12:39
【问题描述】:

C++ 中的常量表达式有一个非常简洁的特性:它们的求值不能有未定义的行为 (7.7.4.7):

表达式 e 是核心常量表达式,除非按照抽象机 ([intro.execution]) 的规则对 e 的求值将求值以下之一:

  • ...

  • 具有未定义行为的操作,如本文档的 [intro] 到 [cpp] [注:包括,例如,有符号整数溢出 ([expr.prop])、某些指针算术 ([expr.add ])、除以零或某些移位操作——结束注];

试图将13! 的值存储在constexpr int 实际上是yields a nice compile error

constexpr int f(int n) 
{
    int r = n--;
    for (; n > 1; --n) r *= n;
    return r;
}

int main() 
{
    constexpr int x = f(13);
    return x;
}

输出:

9:19: error: constexpr variable 'x' must be initialized by a constant expression
    constexpr int x = f(13);
                  ^   ~~~~~
4:26: note: value 3113510400 is outside the range of representable values of type 'int'
    for (; n > 1; --n) r *= n;
                         ^
9:23: note: in call to 'f(3)'
    constexpr int x = f(13);
                      ^
1 error generated.

(顺便说一句,为什么错误说“调用'f(3)'”,而它是对f(13)的调用?..)

然后,我从x 中删除constexpr,但将f 设为consteval。根据the docs

consteval - 指定一个函数是一个立即函数,即每次调用该函数都必须产生一个编译时常量

我确实希望这样的程序会再次导致编译错误。但取而代之的是the program compiles and runs with UB

这是为什么呢?

UPD: 评论者认为这是一个编译器错误。我举报了:https://bugs.llvm.org/show_bug.cgi?id=43714

【问题讨论】:

  • in call to 'f(3)' - 这很奇怪!前任。如果你把f(123)当成警告in call to 'f(119)'
  • 我认为这只是一个错误。该标准明确规定“立即调用应为常量表达式”。但是,也有可能发生了一些更复杂的事情(即,也许该要求将被删除,而 Clang 正在实施新行为)。
  • 编译器错误。这里没什么可看的,继续前进。
  • @JesperJuhl 完成。
  • @StoryTeller 整数是二进制补码,但溢出仍未定义。

标签: c++ undefined-behavior c++20 consteval


【解决方案1】:

这是一个编译器错误。或者,更准确地说,这是一个“未实现”的功能(请参阅the comment in bugzilla):

是的 - 似乎 consteval 尚未实现,根据:https://clang.llvm.org/cxx_status.html

(可能添加了关键字,但没有实际的实现支持)

【讨论】:

    猜你喜欢
    • 2021-10-26
    • 1970-01-01
    • 1970-01-01
    • 2018-08-18
    • 1970-01-01
    • 2021-11-25
    • 1970-01-01
    • 1970-01-01
    • 2012-02-10
    相关资源
    最近更新 更多