Initializer Lists in C++
This type is used to access the values in a C++ initialization list, which is a list of elements of type const T.
Objects of this type are automatically constructed by the compiler from initialization list declarations, which is a list of comma-separated elements enclosed in braces:
auto il = { 10, 20, 30 }; // the type of il is an initializer_list
Notice though that this template class is not implicitly defined and the header <initializer_list> shall be included to access it, even if the type is used implicitly.
initializer_list objects are automatically constructed as if an array of elements of type T was allocated, with each of the elements in the list being copy-initialized to its corresponding element in the array, using any necessary non-narrowing implicit conversions.
The initializer_list object refers to the elements of this array without containing them: copying an initializer_list object produces another object referring to the same underlying elements, not to new copies of them (reference semantics).
The lifetime of this temporary array is the same as the initializer_list object.
Constructors taking only one argument of this type are a special kind of constructor, called initializer-list constructor. Initializer-list constructors take precedence over other constructors when the initializer-list constructor syntax is used:
struct myclass {
myclass (int,int) { /* some code */ };
myclass (initializer_list<int>) { /* some code */ };
};
myclass foo {10,20}; // calls initializer_list ctor
myclass bar (10,20); // calls first constructor
std::initializer_list has the following member functions:
- default constructor
size()begin()end()
std::initializer_list defines the following member types:
| member type | definition |
|---|---|
value_type | The template parameter (T) |
reference | const T& |
const_reference | const T& |
size_type | size_t |
iterator | const T* |
const_iterator | const T* |
An example
#include <initializer_list>
#include <iostream>
#include <vector>
template<class T>
struct S
{
std::vector<T> v;
S(std::initializer_list<T> l) : v(l)
{
std::cout << "constructed with a " << l.size() << "-element list\n";
}
void append(std::initializer_list<T> l)
{
v.insert(v.end(), l.begin(), l.end());
}
std::pair<const T*, std::size_t> c_arr() const
{
return {&v[0], v.size()}; // copy list-initialization in return statement
// this is NOT a use of std::initializer_list
}
};
template<typename T>
void templated_fn(T) {}
int main()
{
S<int> s = {1, 2, 3, 4, 5}; // copy list-initialization
s.append({6, 7, 8}); // list-initialization in function call
std::cout << "The vector now has " << s.c_arr().second << " ints:\n";
for (auto n : s.v)
std::cout << n << ' ';
std::cout << '\n';
std::cout << "Range-for over brace-init-list: \n";
for (int x : {-1, -2, -3}) // the rule for auto makes this ranged-for work
std::cout << x << ' ';
std::cout << '\n';
auto al = {10, 11, 12}; // special rule for auto
std::cout << "The list bound to auto has size() = " << al.size() << '\n';
// templated_fn({1, 2, 3}); // compiler error! "{1, 2, 3}" is not an expression,
// it has no type, and so T cannot be deduced
templated_fn<std::initializer_list<int>>({1, 2, 3}); // OK
templated_fn<std::vector<int>>({1, 2, 3}); // also OK
}