为什么约束函数允许未定义的行为?


16

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

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

  • ...

  • 一种操作,其操作将具有本文档的[引言] [cpp]中指定的未定义的行为[注意:例如,包括有符号整数溢出([expr.prop]),某些指针算术([expr.add],除以零或某些移位操作-尾注];

尝试将13!in 的值存储在constexpr int确实产生一个不错的编译错误

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(13)的调用,却显示“对'f(3)'的调用?”。)

然后,我constexpr从中删除x,但制作f了一个consteval。根据文档

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

我确实希望这样的程序会再次导致编译错误。但是,该程序可以使用UB编译并运行

这是为什么?

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


2
in call to 'f(3)'- 这很奇怪!例如 如果您f(123)发出叮当警告in call to 'f(119)'
KamilCuk

我认为这只是一个错误。该标准明确规定“立即调用应为常量表达式”。但是,也有可能发生一些更复杂的事情(即,也许该要求将被删除,而Clang正在实施新的行为)。
布莱恩

3
编译器错误。这里没什么好看的,离开。
TC

1
@JesperJuhl完成。
米哈伊尔

4
@StoryTeller整数是二进制补码,但是溢出仍然不确定。
巴里

Answers:


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.