This is some kind of follow-up for this topic and deals about a little part of it. As with the previous topic, let\'s consider that our compiler has constexpr
funct
Your examples are all ill-formed.
tl/dr: The initializer is non-constant because it refers to a different temporary each time the function is evaluated.
The declaration:
constexpr std::initializer_list b = { a0, a1, a2 };
creates a temporary array of type const int [3]
(C++11 [dcl.init.list]p5), then binds the std::initializer_list
object to that temporary as if by binding a reference to it (C++11 [dcl.init.list]p6).
Now, by C++11 [expr.const]p4,
For a literal constant expression of array or class type, each subobject [...] shall have been initialized by a constant expression. [...] An address constant expression [...] evaluates to the address of an object with static storage duration.
Since b
has automatic storage duration, when the std::initializer_list
object binds to the const int [3]
temporary, the temporary is also given automatic storage duration, so the initialization of b
is not a constant expression because it refers to the address of an object that does not have static storage duration. So the declaration of b
is ill-formed.
Why GCC accepts some of the constexpr
std::initializer_list
objects
In cases where the initializer is suitably trivial, GCC (and Clang) promote the array to global storage rather than creating a new temporary each time around. However, in GCC, this implementation technique leaks through to the language semantics -- GCC treats the array as having static storage duration, and accepts the initialization (as either an accidental or deliberate extension to the C++11 rules).
Workaround (Clang only)
You can make your examples valid by giving the std::initializer_list
objects static storage duration:
static constexpr std::initializer_list b = { a0, a1, a2 };
This in turn gives static storage duration to the array temporary, which makes the initialization be a constant expression.
Using Clang and libc++ (with constexpr
added to libc++'s
and
in the appropriate places), this tweak of adding static
is sufficient for your examples to be accepted.
Using GCC, the examples are still rejected, with diagnostics such as:
:21:61: error: ‘const std::initializer_list{((const int*)(& _ZGRZ4mainE1c0)), 1u}’ is not a constant expression
Here, _ZGRZ4mainE1c0
is the mangled name of the lifetime-extended array temporary (with static storage duration), and we can see that GCC is implicitly calling the (private) initializer_list
constructor. I am not sure why GCC is still rejecting this.