17

std::initializer_list is constructed by the compiler from a brace-enclosed init list and the size of this list must be a compile time constant.

So why did the committee decide to omit the size from the template arguments? This possibly prevents some optimizations and makes some things impossible (initializing std::array from a std::initializer_list).

pmr
  • 58,701
  • 10
  • 113
  • 156
  • 4
    A very similar question is "why is `std::initializer_list::size` not `constexpr` (anymore) ?" which was asked on clc++m a year ago. – MSalters Aug 18 '11 at 14:05
  • 1
    Re MSalters' 2011 comment, notice that C++14 *does* make `std::initializer_list::size` a `constexpr` function, even though C++11 didn't. http://en.cppreference.com/w/cpp/utility/initializer_list/size – Quuxplusone Jan 22 '14 at 06:17

2 Answers2

15

If initializer_list was defined as std::initializer_list<type, size>, then any function that takes an initializer_list<type>, where type is some concrete type, would now have to be a template function based on that list's size. Or they would have to require that users pass an initializer_list of a specific type and size.

Both of these are pretty unacceptable. Not everyone writes all of their code as templates.

You can initialize a std::array from a braced-init-list ({} with stuff in the middle). But that's not the same thing as a std::intiializer_list. The array class is an aggregate type. It is a struct that contains a single element, which is a public array. Therefore, on a conforming C++11 implementations, this should compile:

std::array<int, 3> myArray = {1, 3, 5};

However, {1, 3, 5} is not a std::initializer_list object; it is merely a braced-init-list, which can be used to initialize appropriate types.

You cannot pass a std::initializer_list object to the constructor of an aggegate (because aggregates have no constructors), but you can use a braced-init-list to invoke aggregate initialization to initialize a std::array, just as you would for any struct containing an array.

The difference between a std::initializer_list and a braced-init-list is a bit like the difference between an int and the literal 0. It's not (usually) legal to implicitly convert an int object into a pointer type, but it is legal to implicitly convert an integer literal 0 into a pointer type. The way braced-init-lists work is like that:

int i = 0;    //Legal
void *j = 0;  //Legal
void *k = i;  //Not legal

std::array<int, 3> myArray = {1, 3, 5};             //Legal
std::initializer_list<int> myInitList = {1, 3, 5};  //Legal
std::array<int, 3> myArray = myInitList;            //Not legal
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Are you sure about initializing `std::array` from `std::initializer_list`? `array x = {1,2,3}` does not work on gcc 4.6 and I cannot infer that this should work from n3242. – pmr Aug 18 '11 at 19:52
  • @pmr: std::array is defined (in N3291) as a struct, and it follows the C++0x rules for an aggregate type. Therefore, it should be initialized via aggregate initialization. So you initialize it as though it were a struct holding an array of 3 elements. I'll update my post to explain this. – Nicol Bolas Aug 18 '11 at 20:10
  • 1
    @Nicol : That's just aggregate initialization -- `initializer_list` is completely orthogonal. – ildjarn Aug 18 '11 at 20:17
  • @ildjarn: Technically, yes. But users don't care if it uses a `std::initializer_list` object or aggregates or whatever; all they care about is that it *works*. That they can use {} syntax to statically initialize a `std::array`. – Nicol Bolas Aug 18 '11 at 20:26
  • 4
    @Nicol : They do for purposes of e.g. writing a `make_array` function, as has been brought up multiple times on SO. In any case, I find it misleading to say "*You can initialize a `std::array` from an initializer list*" when what you really mean is just that `std::array` can be initialized with superficially similar syntax. – ildjarn Aug 18 '11 at 20:32
  • 2
    @ildjarn: Which is why the statement is followed by "sort of" and doesn't mention `std::initializer_list` the type, but simply "an initializer list". Notice the lack of an underscore. – Nicol Bolas Aug 18 '11 at 22:07
  • What I'm wondering is that why one allowed to instantiate std::initializer_list without size requirements if its a statically allocated struct? Or is it dynamically allocated? – glades May 25 '22 at 10:10
  • @glades: `initializer_list` is not "statically allocated". The array that `initializer_list` *references* may be statically allocated. It is at the very least local to the context which contains the braced-init-list. – Nicol Bolas May 25 '22 at 13:31
8

One upside of the existing system is that you can export functions which take an initializer_list from a DLL. If it were templated on the size, they would have to be shipped as source.

Puppy
  • 144,682
  • 38
  • 256
  • 465