list initialization enables uniform way of initializing scalar and complex objects such as ints, doubles, structs, classes using a pair of braces {}. A new data type called initializer_list is used for such initialization.
Details
initializer_list
The C++11 standard library introduced a new template based type initializer_list <T> to handle variable-length {}-lists. initializer_list is used to aid uniform initialization. It's automatically created when braces {} are used to initialize.
The initializer_list can be also instantiated to define homogeneous lists of varying lengths and passed as arguments. Note that these are not mutable. They can be iterated using iterators. Indexing is not possible.
auto x0 = {}; // error (no element type)
auto x1 = {1}; // initializer_list<int>
auto x2 = {1.,2.}; // initializer_list<double>
auto x3 = {"1","2","3"}; // initializer_list<char*>
auto x4 = {1,2.0}; // error : nonhomogeneous list
*x2.begin()=10; //error
int high_value(initializer_list<int> val)
{
int high = numeric_traits<int>lowest();
if (val.size()==0)
return high;
for (auto x : val)
if (x>high)
high = x;
return high;
}
int v1 = high_value({1,2,3,4,5,6,7});
int v2 = high_value({-1,2,v1,4,-9,20,v1});
Classes can also provide a constructor accepting initializer_list. In this case, the compiler will prefers this type of constructor for qualified list construction.
struct P
{
int i;
int j;
int k;
P(int, int){}
P(initializer_list<int> lst)
{
i=j=k=0;
auto itr = lst.begin();
if (itr != lst.end())
{
i=*itr++;
}
if (itr != lst.end())
{
j=*itr++;
}
if (itr != lst.end())
{
k=*itr++;
}
}
};
P p{1,2,3}; //i=1 j=2 k=3
P p2={4,5}; //i=1 j=2. will not call P(int, int)
list - initialization
eliminates most vexed parsing
mvp happens during compilation of code such as below.
The compiler throws an error as it cannot resolve the line highlighted below is a variable declaration or a function declaration.
TimeKeeper time_keeper(Timer ()); //error
This is depicted in the example 11.
After uniform initialization as shown below, this code compiles without errors.
TimeKeeper time_keeper(Timer {});
This is depicted in the example 12.
eliminates narrowing errors
Enables overflow checks. During compilation, the compiler reports errors for c, i and s for overflow.
char {0xf0}; //narrowing error
short {0xffff}; //narrowing error int {2.0}; //narrowing error
unqualified lists
A unqualified list is used where an expected type is unambiguously known. It can be used as an
expression only as:
- A function argument
- A return value
- The right-hand operand of an assignment operator (=, +=, ∗=, etc.)
- A subscript
int v {7}; // initializer (direct initialization)
int v2 = {7}; // initializer (copy initialization)
int v3 = m[{2,3}]; // assume m takes value pairs as subscripts
v ={8}; //right-hand operand of assignment
v += {88}; //right-hand operand of assignment
{v} = 9; // error : not left-hand operand of assignment
v = 7+{10}; // error : not an operand of a non-assignment operator
f({10.0}); // function argument
return {11}; // return value
qualified lists
{}-list can be used as constructor arguments, as if used in a ()-list. List elements are not copied except as by-value constructor arguments.
struct S { int a; double b; };
S v {7,8.5}; //direct initialization of a variable
v = S{7,8.5}; // assign using qualified list
S* p = new S{7,8.5}; // construct on free store using qualified list
uniform container initialization
Containers such as vector, list and map can be initialized with a list of the objects they are intended to contain.
std::vector<int> {1,2,3,4,5}; std::vector<int> {1,2.0,3,4,5}; //error 2.0 is not int std::list<std::string> {"mon","tue","wed","thu","fri","sat","sun"}; std::map<std::string,int> {{"a",97},{"b",98},{"c",99}};
//internally compilers generates code for the assignment //for example vector<double> v = {1, 2, 3.14}; //becomes similar to //const double temp[] = {double{1}, double{2}, 3.14 } ; //const initializer_list<double> tmp(temp,sizeof(temp)/sizeof(double)); //vector<double> v(tmp);
usages examples
In the example 13 below and as seen in its console output. the compiler initializes the data members of the POD object based on their position in the class.
In the example 14 below and seen in its console output. the compiler calls different constructors of POD based on the data types.
In the example 15 below and its console output. the POD is constructed using an initializer_list constructor.
Side effects
The STL container classes such as vector, provide list initialization constructors. However it can introduce unwanted side effects as shown in the example 16 and its console output below. Therefore parenthesis () based constructors should be used where needed.
No comments:
Post a Comment