Fedor
Fedor

Reputation: 21231

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

A colleague of mine showed me this shocking C++20 program:

#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 cannot build it due to the error:

Error: symbol `_Z1pIiEiT_' is already defined

Clang builds the program successfully and prints 11( https://gcc.godbolt.org/z/1Gf5vj5oo ). So static_assert(q() == 0) was successfully checked, but std::cout << q() still printed 1. How can this be?

Visual Studio 2019 16.10.4 behaves even more weirdly. In Release configuration it prints also 11, and in Debug configuration it prints 00. And here in both cases run-time values of functions differ from their compile-time values, verified by static_assert.

The only explanation I can think of is that all these are compiler bugs, and a constexpr function must always produce the same result at compile- and run-time. Is that right?

Upvotes: 9

Views: 287

Answers (1)

Davis Herring
Davis Herring

Reputation: 39818

While this program is contrived, it is valid and does what you think (prints “01”), so all compilers are wrong. GCC is failing to mangle the requires true into the name of the second p, MSVC/Debug is failing to select that more-constrained overload, and the other two cases are failing to use the lookup result from q (which is not itself a template subject to multiple points of instantiation).

As for the question title, std::is_constant_evaluated does allow constant evaluation to produce different results from runtime evaluation. Use this power only for good!

Upvotes: 5

Related Questions