相关疑难解决方法(0)

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

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;
}
Run Code Online (Sandbox Code Playgroud)

输出:

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 …
Run Code Online (Sandbox Code Playgroud)

c++ undefined-behavior c++20 consteval

16
推荐指数
1
解决办法
308
查看次数

是否允许编译器在运行时调用立即(恒定)函数?

这可能是一个愚蠢的问题,但我感到困惑。我有一种感觉,立即(consteval)函数具有在编译时被执行,我们根本无法看到它的身体在二进制。

这篇文章显然支持我的感觉:

这意味着[immediate]函数仅在编译时可见。该函数不会发出符号,您不能使用该函数的地址,并且调试器之类的工具将无法显示它们。在这种情况下,立即函数类似于宏。

Herb Sutter的出版物中也可以找到类似的强烈主张:

请注意,C ++ 20草案已经包含了第一轮与反射相关的工作,并纳入了标准:确保函数在编译时运行的 consteval函数,这些函数来自于反射工作,并且专门用于处理反射信息。

但是,有很多证据对此事实不太清楚。

来自cppreference

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

这并不意味着它已经在只有编译时被调用。

P1073R3提案中

现在,人们普遍同意,将来对反射的语言支持应该使用constexpr函数,但是由于“反射函数”通常必须在编译时进行评估,因此实际上它们很可能是立即函数。

似乎这意味着我的想法,但仍未明确说出。根据同一建议:

但是,有时我们想表达的是,函数在被调用时(直接或间接)应始终产生常数,而非常数结果应产生错误。

同样,这并不意味着仅在编译时就必须评估函数。

这个答案

您的代码必须产生一个编译时常数表达式。但是编译时常量表达式在您使用它的上下文中不是可观察的属性,并且在链接甚至运行时执行它都没有副作用!在没有任何阻止的情况下

最后,有一个实时演示,其中consteval在运行时明确调用了函数。但是,我希望这是由于constevalclang尚未正确支持该事实,并且该行为实际上是不正确的,就像为什么consteval函数允许未定义的行为?

更准确地说,我想听听被引用文章的以下哪些陈述是正确的:

  1. 立即函数仅在编译时可见(并且无法在运行时评估)
  2. 不会为即时功能发出符号
  3. 诸如调试器之类的工具将无法显示即时功能

c++ language-lawyer c++20 consteval

6
推荐指数
2
解决办法
186
查看次数