9

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?

4
  • 8
    You have 2 overloads of p, with only one visible at the q point of cal. There is going to be a mess with overloads and template instantiation. I suspect ill formed ndr. q has different meaning at definition spot and at end of compilation unit. Usually that is bad. Commented Aug 1, 2021 at 12:03
  • Thanks. I actually expected that if the compiler can check all function results in compile-time as static_asserts prove, why it cannot use the same values in run time? Commented Aug 1, 2021 at 13:52
  • The freedom to pick evaluate which overload selected at either point of definition or end of compilation unit saves compilers complexity and time. You are responsible to not violate that. Sensible code organization; grouping non-adl overload definitions together, defining signatures before implmentations - makes that easy. Tge sample code you provided is bad code, and compliers choke on it. Commented Aug 1, 2021 at 18:14
  • Could you please crarify, what you mean by "bad code"? Yes, the code does not look practical, but only to simplify and reduce it for the purpose of this discussion. If the code violates something from the standard, please explain it. Commented Aug 1, 2021 at 19:16

1 Answer 1

5

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!

Sign up to request clarification or add additional context in comments.

6 Comments

Template function bodies must evaluate to the same meaning at their definition amd end of compilation unit, no?
Hmm, only for adl purposes.
@Yakk-AdamNevraumont: What “template function” do you mean?
p and q are template functions. auto arguments make them template functions.
@Yakk-AdamNevraumont q is not a template.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.