[dcl.init.list]/6
(from C++20 draft N4860) states that
The array has the same lifetime as any other temporary object (6.7.7), except that initializing an initializer_list object from the array extends the lifetime of the array exactly like binding a reference to a temporary.
They include these examples:
void f() {
std::vector<cmplx> v2{ 1, 2, 3 };
std::initializer_list<int> i3 = { 1, 2, 3 };
}
struct A {
std::initializer_list<int> i4;
A() : i4{ 1, 2, 3 } {} // ill-formed, would create a dangling reference
};
The standard continues, in the same paragraph, with
For v1 and v2, the initializer_list object is a parameter in a function call, so the array created for { 1, 2, 3 } has full-expression lifetime. For i3, the initializer_list object is a variable, so the array persists for the lifetime of the variable. For i4, the initializer_list object is initialized in the constructor's ctor-initializer as if by binding a temporary array to a reference member, so the program is ill-formed (11.10.2).
(emphasis mine)
In your example, I believe, it is equivalent to example i3
; thus the use of the initializer is valid. However, the constexpr
, I think, is what is causing the issue. If you remove constexpr
, MSVC, g++, and clang are all happy and execute the code.
I might be wrong, but I'd actually think this is a bug in MSVC. When running the code, MSVC exits with STATUS_ACCESS_VIOLATION
. I'm assuming this is because the addresses are no longer valid that it's trying to reference when printing -- using int
instead of const char*
consistently printed 0
for me, though I'd expect that to be more random like access uninitialized memory.