为什么 `constexpr` 函数会在编译时和 运行 时产生不同的结果?

Why can a `constexpr` function produce different results at compile- and run-time?

我的一位同事向我展示了这个令人震惊的 C++20 程序:

#include <iostream>

constexpr int p(auto) { return 0; }
constexpr int q() { return p(0); }
constexpr int p(auto) requires true { return 1; }

static_assert(p(0) == 1);
static_assert(q() == 0);

int main()
{
    std::cout << q() << p(0) << '\n';
}

由于错误,GCC 无法构建它:

Error: symbol `_Z1pIiEiT_' is already defined

Clang 成功构建程序并打印 11( https://gcc.godbolt.org/z/1Gf5vj5oo )。所以 static_assert(q() == 0) 检查成功,但是 std::cout << q() 仍然打印 1。怎么会这样?

Visual Studio 2019 16.10.4 表现得更奇怪了。在 Release 配置中它也打印 11,而在 Debug 配置中它打印 00。在这两种情况下,函数的 运行 时间值与其编译时值不同,由 static_assert.

验证

我能想到的唯一解释是所有这些都是编译器错误,并且 constexpr 函数必须始终在编译时和 运行 时产生相同的结果。是吗?

虽然这个程序是人为设计的,但它 有效 并且按照您的想法行事(打印“01”),因此所有编译器都是错误的。 GCC 无法 manglerequires true 转换为第二个 p 的名称,MSVC/Debug 无法 select more-constrained 重载,其他两种情况未能使用 lookup 结果来自 q (它本身不是模板主题到多个实例化点)。

至于问题标题,std::is_constant_evaluated 允许 持续评估以产生与运行时评估不同的结果。只为善用这种力量!