constexpr
说明符声明可以在编译时计算函数或变量的值。 constexpr
函数的唯一用例是它能够在编译时解析。或者更准确地说,能够用其结果初始化 constexpr
变量。如果将 constexpr
函数的结果存储到 constexpr
变量中,它会强制该函数成为纯函数(看起来像,但不确定)。
为什么功能
add
可以被标记为constexpr
?
int global=200;
constexpr int add(int a) {
global += a; //works perfectly at run-time but no way to run at compile time
return global;
}
int main() {
constexpr int a = add(1); // will not run since attempts to access run-time storage, global not const and so on
int b = add(1); // works but at run-time only yet marked as constexpr
}
此类功能的用例是什么;为什么它被允许呢?
constexpr
函数可以与运行时输入一起使用,因为允许在运行时使用。
然而,在函数体中允许非常量运行时变量的目的是什么,这会破坏 constexpr
的全部目的?
有人知道为什么标准允许这样的功能吗?
来自 C++20 标准,[dcl.constexpr] p6(强调我的)在 C++23 之前,
对于既不是默认值也不是模板的 constexpr 函数 [...],如果不存在参数值,使得函数 [...] 的调用可以是核心常量表达式的计算子表达式,[...] ],程序格式错误,无需诊断。
因此不需要诊断。
Clang/gcc 成功诊断问题演示。
在C++23中,现在拥有这样的函数是合法的
有可能编写一个 constexpr 函数,其调用永远无法满足核心常量表达式的要求。
原理可以在论文中找到放宽一些
constexpr
限制。
粗略地说,它是面向未来的(一般情况下):
版本 N 中不是
constexpr
的函数在版本 N+1 中可能会变成 constexpr
。
我想你的问题是:“为什么函数在定义时不会被拒绝,而只有在 constexpr 上下文中调用时才被拒绝?” 想象一下你的函数看起来像这样:
int global = 200;
constexpr int add(int a) {
if (a > 42) {
global += a;
return global;
}
return a;
}
可以在编译时对小于或等于 42 的任何参数求值此函数。检查是否可以在编译时对每个可能的输入求值该函数对编译器有很多要求,因此只需要在以下情况下进行:函数实际上是在编译时调用的。