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) 这可能是一个愚蠢的问题,但我感到困惑。我有一种感觉,立即(consteval)函数具有在编译时被执行,我们根本无法看到它的身体在二进制。
这篇文章显然支持我的感觉:
这意味着[immediate]函数仅在编译时可见。该函数不会发出符号,您不能使用该函数的地址,并且调试器之类的工具将无法显示它们。在这种情况下,立即函数类似于宏。
在Herb Sutter的出版物中也可以找到类似的强烈主张:
请注意,C ++ 20草案已经包含了第一轮与反射相关的工作,并纳入了标准:确保函数在编译时运行的 consteval函数,这些函数来自于反射工作,并且专门用于处理反射信息。
但是,有很多证据对此事实不太清楚。
来自cppreference:
consteval-指定一个函数为立即函数,也就是说,对该函数的每次调用都必须产生一个编译时常量。
这并不意味着它已经在只有编译时被调用。
现在,人们普遍同意,将来对反射的语言支持应该使用constexpr函数,但是由于“反射函数”通常必须在编译时进行评估,因此实际上它们很可能是立即函数。
似乎这意味着我的想法,但仍未明确说出。根据同一建议:
但是,有时我们想表达的是,函数在被调用时(直接或间接)应始终产生常数,而非常数结果应产生错误。
同样,这并不意味着仅在编译时就必须评估函数。
从这个答案:
您的代码必须产生一个编译时常数表达式。但是编译时常量表达式在您使用它的上下文中不是可观察的属性,并且在链接甚至运行时执行它都没有副作用!在没有任何阻止的情况下
最后,有一个实时演示,其中consteval在运行时明确调用了函数。但是,我希望这是由于constevalclang尚未正确支持该事实,并且该行为实际上是不正确的,就像为什么consteval函数允许未定义的行为?
更准确地说,我想听听被引用文章的以下哪些陈述是正确的: