Why is the size not a template argument of std::initializer_list?
Asked Answered
H

2

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).

Hewett answered 18/8, 2011 at 13:45 Comment(2)
A very similar question is "why is std::initializer_list::size not constexpr (anymore) ?" which was asked on clc++m a year ago.Hewet
Re MSalters' 2011 comment, notice that C++14 does make std::initializer_list::size a constexpr function, even though C++11 didn't. en.cppreference.com/w/cpp/utility/initializer_list/sizeSticker
S
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.

Sickert answered 18/8, 2011 at 13:53 Comment(1)
Along the same lines: it can cause some non-trivial bloat.Hewet
C
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
Concurrence answered 18/8, 2011 at 18:31 Comment(8)
Are you sure about initializing std::array from std::initializer_list? array<int, 3> x = {1,2,3} does not work on gcc 4.6 and I cannot infer that this should work from n3242.Hewett
@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.Concurrence
@Nicol : That's just aggregate initialization -- initializer_list is completely orthogonal.Obstipation
@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.Concurrence
@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.Obstipation
@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.Concurrence
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?Animalize
@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.Concurrence
S
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.

Sickert answered 18/8, 2011 at 13:53 Comment(1)
Along the same lines: it can cause some non-trivial bloat.Hewet

© 2022 - 2024 — McMap. All rights reserved.