Initializer lists
C++03 has partial support for initializer lists, allowing you to use initializer lists for simple aggregate data types (structs and C-style arrays):
struct Employee
{
int nID;
int nAge;
float fWage;
};
Employee sJoe = {1, 42, 60000.0f};
int anArray[5] = { 3, 2, 7, 5, 8 };
However, this doesn’t work for classes, as classes must be initialized via constructors using the function call syntax. This leads to the following inconsistency:
int anArray[5] = { 3, 2, 7, 5, 8 }; // ok
std::vector<int> vArray[5] = {3, 2, 7, 5, 8}; // not okay in C++03
C++11 extends initializer lists so they can be used for all classes. This is done via a new template class called std::initializer_list, which is part of the <initializ_list> header file. If you use an initializer list on a class, C++11 will look for a constructor with a parameter of type std::initializer_list
std::vector<int> vArray[5] = {3, 2, 7, 5, 8}; // calls constructor std::vector<int>(std::initializer_list<int>);
All of the relevant standard library classes in C++11 have been updated to accept initializer lists, so you can start using them immediately (assuming your compiler supports them — as of the time of writing, Visual Studio 2010 does not).
You can also add initializer_list constructors to your own classes, and use an iterator to step through the members of the initializer list:
#include <vector>
#include <initializer_list>
using namespace std;
template <typename T>
class MyArray
{
private:
vector<T> m_Array;
public:
MyArray() { }
MyArray(const initializer_list<T>& il)
{
// Manually populate the elements of the array from initializer_list x
for (auto x: il) // use range-based for statement to iterate over the elements of the initializer list
m_Array.push_back(x); // push them into the array manually
}
};
int main()
{
MyArray<int> foo = { 3, 4, 6, 9 };
return 0;
}
Because std::vector has an initializer_list constructor in C++11, we could also have let the vector constructor handle initialization itself:
MyArray(const std::initializer_list<T>& x): m_Array(x) // let vector constructor handle population of mArray
{
}
Note that because initializer_list has iterator functions begin() and end(), we can use the new range-based for statement to iterate through them.
A few oddities to note: while initializer_list supports the iterator functions begin() and end(), it doesn’t support const interator functions cbegin() and cend(). Initializer_list also doesn’t provide direct random access to data members via operator[].
You can also use initializer lists a function parameters, and access the elements in the same way:
int sum(const initializer_list<int> &il)
{
int nSum = 0;
for (auto x: il) // use range-based for statement to iterate over the elements of the initializer list
nSum += x;
return nsum;
}
cout << sum( { 3, 4, 6, 9 } );
Uniform initialization
As noted above, C++03 is inconsistent in how it lets you initialize different types of data. Initializer lists go a long way to helping making initialization of data more consistent. However, C++11 has one more trick up its sleeve called uniform initialization. Unlike initializer lists, which take the form:
type variable = { data, elements };
The uniform initialization syntax takes the following form:
type variable { data, elements }; // note: no assignment operator
This style of initialization will work for both plain aggregate data types (structs and C-style arrays) and classes. For classes, the following rules are observed:
- If there is an initialization_list constructor of the appropriate type, that constructor is used
- Otherwise the class elements are initialized using the appropriate constructor
For example:
class MyStruct
{
private:
int m_nX;
float m_nY;
public:
MyStruct(int x, float y): m_nX(x), m_nY(y) {};
};
MyStruct foo {2, 3.5f};
Since MyStruct does not have an initializer_list constructor, it will next check to see if there’s a constructor that takes parameters of type (int, float). MyStruct does, so that constructor is called.
Although it may initially seem like the uniform initialization syntax is always preferable to the standard constructor syntax, there are cases where the two can provide different results:
std::vector<int> v1(8); // creates an empty vector of size 8, using the int constructor
std::vector<int> v1{8}; // creates a one-element vector with data value 8, using the initializer_list constructor
This happens because the initializer_list constructor takes precedence over other constructors when doing uniform initialization.
You can also use the uniform initialization syntax when calling or return values in functions:
void useMyStruct(MyStruct x)
{
}
useMyStruct({2, 3.5f}); // use uniform initialization to create a MyStruct implicitly
MyStruct makeMyStruct(void)
{
return {2, 3.5f}; // use uniform initialization to create a MyStruct implicitly
}
Initializer lists vs initialization lists
The choice of the name “initializer list” is unfortunate, as it’s very easy to get confused with the “initialization list”, which is a similar concept. Here’s the difference:
An initialization list is used to do implicit assignments to class variables as part of a constructor:
MyStruct(int x, float y): m_nX(x), m_nY(y) {}; // m_nX and m_nY are part of the initialization list
An initializer list is a list of initializers inside brackets ( { } ) that can be used to initialize simple aggregate data types and classes that implement std::initializer_list:
std::vector<int> vArray[5] = {3, 2, 7, 5, 8}; // vArray initialized using an initializer_list
B.5 — Delegating constructors
|
Index
|
B.3 — Range-based for statements and static_assert
|
B.5 — Delegating constructors
Index
B.3 — Range-based for statements and static_assert 
[...] B.4 — Initializer lists and uniform initialization [...]
Capitalization error in the sample code:
return nsum;
You can’t write “std::vector vArray[5] = {3, 2, 7, 5, 8};” It means that you are creating an array of five vectors, and each is initialized with int. This causes compilation error “could not convert ‘3’ from ‘int’ to ‘std::vector’” (repeat 4 times for every vector).
The proper form is: “std::vector vArray = {3, 2, 7, 5, 8};”. Vector’s constructor will know the number of elements by using http://en.cppreference.com/w/cpp/utility/initializer_list/size