Initializer lists

So far in this book, initializer lists have been treated as a kind of C++11 construct, a bit like built-in arrays. In fact, when you use the initializer list syntax using braces, the compiler actually creates an instance of the templated initialize_list class. If an initializer list is used to initialize another type (for example, to initialize a vector), the compiler creates an initialize_list object with the values given between the braces, and the container object is initialized using the initialize_list iterators. This ability to create an initialize_list object from a braced initializer list can be used by to give a function a variable number of parameters, albeit all of the parameters must be of the same type:

    #include <initializer_list> 

int sum(initializer_list<int> values)
{
int sum = 0;
for (int i : values) sum += i;
return sum;
}

int main()
{
cout << sum({}) << endl; // 0
cout << sum({-6, -5, -4, -3, -2, -1}) << endl; // -21
cout << sum({10, 20, 30}) << endl; // 60
return 0;
}

The sum function has a single parameter of initializer_list<int>, which can only be initialized with a list of integers. The initializer_list class has very few functions because it only exists to give access to the values in the braced list. Significantly, it implements a size function that returns the number of items in the list, and begin and end functions that return a pointer to the first item in the list, and to the position after the last item. These two functions are needed to give iterator access to the list, and it enables you to use the object with the ranged-for syntax.

This is typical in the C++ Standard Library. If a container holds data in a contiguous block of memory, then pointer arithmetic can use the pointer to the first item and a pointer immediately after the last item to determine how many items are in the container. Incrementing the first pointer gives sequential access to every item, and pointer arithmetic allows random access. All containers implement a begin and end function to give access to the container iterators.

In this example, the main function calls this function three times, each time with a braced initializer list, and the function will return a sum of the items in the list.

Clearly this technique means that each item in the variable parameter list has to be the same type (or a type that can be converted to the specified type). You would have the same result if the parameter had been a vector; the difference is that an initializer_list parameter requires less initialization.