Consider this code:
vector<int> v = {11,22,33,44,55};
{11,22,33,44,55}
?
initializer_list
{11,22,33,44,55}
is an object of the type
initializer_list<int>
.
2.71828
is a double
.
iterator
.size()
.begin()
.end()
.empty()
, for are no empty initializer lists.
initializer_list<
what?>
Why is the name so god-awful long?
init
, that breaks many
user programs that already use init
.
Since an initializer_list
has iterators, .begin()
, and .end()
,
we can use it in a for
loop:
for (auto v : {11,22,33,44,55}) cout << v << ' ';
11 22 33 44 55
or, more explicitly:
auto il = {11,22,33,44,55}; auto it = il.begin() + 3; cout << *it << '\n';
44
or, even:
auto il = {11,22,33,44,55}; cout << *(il.begin()+3) << '\n';
44
So, how does this work?
unordered_set<int> us = {345,678,901,234,567,890}; for (auto v : us) cout << v << ' ';
890 567 234 901 678 345
us
.
initializer_list
The ctor must be this:
unordered_set(const initializer_list<value_type> &);
value_type
is a typedef
for the
type being stored by the vector.
unordered_set<value_type> &operator=(const initializer_list<value_type> &)
{ … }
for your container, you must write methods:
class Hundred { int data[100]; public: int &operator[](int n) { return data[n]; } }; Hundred h; h[1] = 123; h[4] = 456; cout << h[1]+h[4] << '\n';
579
class Hundred { int data[100]; public: int &operator[](int n) { return data[n]; } }; Hundred h = {11,22,33,44,55}; cout << h[1]+h[4] << '\n';
c.cc:7: error: could not convert '{11, 22, 33, 44, 55}' from '<brace-enclosed initializer list>' to 'main()::Hundred'
class Hundred { int data[100]; public: Hundred(const initializer_list<int> &il) { copy(il.begin(), il.end(), data); } int &operator[](int n) { return data[n]; } }; Hundred h = {11,22,33,44,55}; cout << h[1]+h[4] << '\n';
77
class Hundred { int data[100]; public: Hundred(const initializer_list<int> &il) { copy(il.begin(), il.end(), data); } int &operator[](int n) { return data[n]; } }; Hundred h = {11,22,33,44,55}; cout << h[1]+h[4] << '\n'; h = {6,7,8,9}; cout << h[2] << '\n';
77 8
How did that work?
class Hundred { int data[100]; public: Hundred(const initializer_list<int> &il) { *this = il; } Hundred &operator=(const initializer_list<int> &il) { copy(il.begin(), il.end(), data); return *this; } int &operator[](int n) { return data[n]; } }; Hundred h = {11,22,33,44,55}; cout << h[1]+h[4] << '\n'; h = {6,7,8,9}; cout << h[2] << '\n';
77 8
That’s better.
Of course, sometimes, a brace is just a brace:
int a[5] = {11, 22, 33}; // initializer_list<int>? cout << a[0] + a[2] << '\n';
44
Or, a more brutal example:
cout << {11,22,33}.size() << '\n';
c.cc:1: error: expected primary-expression before '{' token
Somehow, the compiler figures it out.
Here’s a cheap way to learn the type of anything:
auto a = {1.2, 3.45}; throw a;
terminate called after throwing an instance of 'std::initializer_list<double>' SIGABRT: Aborted
throw 1e6;
terminate called after throwing an instance of 'double' SIGABRT: Aborted
throw 1234567890;
terminate called after throwing an instance of 'int' SIGABRT: Aborted
throw 123456789012345;
terminate called after throwing an instance of 'long' SIGABRT: Aborted
throw 'a';
terminate called after throwing an instance of 'char' SIGABRT: Aborted
throw "b";
terminate called after throwing an instance of 'char const*' SIGABRT: Aborted
throw "c"s;
terminate called after throwing an instance of 'std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >' SIGABRT: Aborted