Why isn't `std::initializer_list` defined as a literal type?

C++Language LawyerC++14Initializer ListConstexpr

C++ Problem Overview


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?

C++ Solutions


Solution 1 - C++

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.

Solution 2 - C++

I remember shortly after C++11 came out I was creating an initializer_list whose individual members allocated dynamic memory, so they had non-trivial d'tors, therefore the initializer_list has a non-trivial d'tor. And there was some circumstance, I think I threw while the initializer_list was partially constructed, where the built part didn't get destroyed, causing a memory leak. I'm sure the compilers have been fixed by now.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionChristopherCView Question on Stackoverflow
Solution 1 - C++OmnipotentEntityView Answer on Stackoverflow
Solution 2 - C++Bill ChapmanView Answer on Stackoverflow