I have the following infinitely recursive constexpr function:
constexpr int foo(int x) { return foo(x + 1); } Then I found that
int main() { static int x = foo(5); static int y = std::integral_constant<int, foo(5)>::value; static constinit int z = foo(5); } the compiler (GCC13, on Ubuntu 22.04) reports error on the initialization of y and z due to compile-time infinite recursion, but no error for x. If we remove the declarations for y and z and then run the program, Address Boundary Error is caused.
Here 5 is a constant expression, but the initialization of x with foo(5) is not performed in compile-time. Why?
What's more, I tried to modify foo:
constexpr int foo(int x) { if (std::is_constant_evaluated()) return 42; return foo(x + 1); } Then I found that x is initialized to 42, with no compile-time or run-time infinite recursions, which indicates that it happens at compile-time this time.
So, is the initializer foo(5) for x evaluated at compile-time? Is this initialization static initialization or dynamic initialization? What are the actual rules about that?
Moreover, I'm not so familiar with constinit. The reason for initializing y with std::integral_constant is that we want to ensure static initialization. Can I say that writing constinit is always a safe and modern alternative to it?
constexprdoesn't guarantee/ensure that it must/will be evaluated at compile time.static constexpr.constexpr.