This is a follow-up of this question: Is it legal to declare a constexpr initializer_list object?.
Since C++14, the std::initializer_list
class has all of its methods marked with constexpr
. It seems natural to be able to initialize an instance by doing
constexpr std::initializer_list<int> list = {1, 2, 3};
but Clang 3.5 complains about list
not being initialized by a constant expression.
As dyp pointed out in a comment, any requirement for std::initializer_list
to be a literal type seem to have vanished from the specs.
What's the point of having a class fully defined as constexpr if we can't even initialize it as such? Is it an oversight in the standard and will get fixed in the future?
The standard committee seems to intend on initializer_list
being a literal type. However, it doesn't look like it's an explicit requirement, and seems to be a bug in the standard.
From § 3.9.10.5:
A type is a literal type if it is:
- a class type (Clause 9) that has all of the following properties:
- - it has a trivial destructor,
- - it is an aggregate type (8.5.1) or has at least one constexpr constructor or constructor template that is not a copy or move constructor, and
- - all of its non-static data members and base classes are of non-volatile literal types.
From § 18.9.1:
namespace std {
template<class E> class initializer_list {
public:
/* code removed */
constexpr initializer_list() noexcept;
// No destructor given, so trivial
/* code removed */
};
}
This satisfies the first and second requirements.
For the third requirement though:
From § 18.9.2 (emphasis mine):
An object of type initializer_list<E>
provides access to an array of objects of type const E
. [Note: A pair of pointers or a pointer plus a length would be obvious representations for initializer_list
. initializer_list
is used to implement initializer lists as specified in 8.5.4. Copying an initializer list does not copy the underlying elements.
—end note]
So there is no requirement for the private members of the implementation of initializer_list
to be non-volatile literal types; however, because they mention that they believe a pair of pointers or a pointer and a length would be the "obvious representation," they probably didn't consider that someone might put something non-literal in the members of initializer_list
.
I'd say that it's both a bug in clang and the standard, probably.