Are some C++ standard library constexpr functions implicitly allowed to be consteval since C++20?

165 views Asked by At

Since C++20, there are immediate functions, whose addresses can't be taken in many cases (P1073R3); and most standard library functions are made non-addressable (P0551R3).

Also, there are some constexpr standard function always returning the same constant value (e.g. static member functions of standard std::numeric_limits specializations, std::barrier<F>::max), and none of them is addressable.

Can implementations conformingly change these functions to consteval?

I intended to make such a change in standard library implementations and opened a discussion in MSVC STL's repo, without receiving any answer so far. And I also wonder whether such change is an improvement, since it possibly reduces the size of symbol tables.

1

There are 1 answers

1
Jan Schultke On

Can implementations conformingly change these functions to consteval?

It depends on the individual function. If there are any parameters, then the answer is no:

consteval int f(int i) { return i; }

constexpr int g(int i) {
    // error: call to consteval function 'f(i)' is not a constant expression
    return f(i) + 1;
}

This happens because a consteval function must only be called with compile-time arguments (this is an over-simplification, it's a bit more complicated) and a constexpr function can have parameters which exist only at runtime. See also P1938R3: ยง3.1 Interaction between constexpr and consteval

That being said, consteval functions with no parameters which are not explicitly addressable can be made consteval, since there is no observable difference between a constexpr and consteval function invocation with no arguments. It would be a classic case of the "as-if rule". See also: What exactly is the "as-if" rule?

However, it would be an ABI-break to do this retroactively. If there are existing applications that make a call to say, std::numeric_limits<float>::max(), this call would produce a linker error because consteval functions don't get emitted into the library. Therefore, implementers may be hesitant to modify existing functions like that. Of course, this refers to debug builds, where ::max() hasn't been inlined. See also: P2028: What is ABI, and What Should WG21 Do About It?