previous 10-Minute Solution demonstrated the new initialization rules of C++09, which enable you to initialize standard containers (among the rest) in the following manner:
vector scores = {89, 76, 98, 93}; //C++09
A new constructor type called a sequence constructor makes this syntax possible. The following sections will show how to enable the ={val1,val2,…} initialization syntax by adding a sequence constructor to your homemade classes.
Unlike C++09 Standard Library containers, your homemade container classes don’t support the new initializer list syntax.
Adding a sequence constructor to your homemade container classes will allow you to initialize instances of those classes similarly to the new initializers in the C++09 Standard Library containers.
I Want C++09 Containers’ Easy Initialization
Suppose you designed a polymorphic container class with certain operations that C++09 standard container classes don’t support. In all other aspects, however, your homemade container has the same interface as a standard container:
template class MyVector{ T* elements; size_t n;public: virtual void reserve(size_t n); //polymorphic T& operator[] (int idx); size_t size() const;//...};
Here’s the snag. Unlike with standard C++09 container classes, populating a MyVector object in your homemade container is an arduous task. You first need to default-construct MyVector and then call push_back() or assign(). The following code demonstrates the difference between standard C++09 containers and homemade containers:
//easy initialization of a standard C++09 container std::vector vi={5,6,7,8}; //alas, "initializing" MyVector is tedious and bug proneint arr[]={0,2,4,8}; MyVector vi; vi.assign(arr, arr+4);
Now suppose you want MyVector to support the same convenient initialization syntax that C++09 containers provide. What is the secret ingredient that C++09 containers use to enable such easy initialization? Answer: Sequence constructors.
Sequence Constructors, The Secret Ingredient
Standard containers inherit their convenient initialization syntax from the newly added sequence constructors. A sequence constructor takes a single argument of type std::initializer_list
#include struct C{ //initialize C with doubles C(std::initializer_list); };//usageC c1={1.5,0.99,23.45,-1.87};
Before continuing with the implementation of MyVector’s sequence constructor, an explanation of how initializer_list performs its magic may be helpful. It’s much simpler than you think!
Inside initializer_list
Initializer_list has two constructors and three member functions that grant access to its range:
template class initializer_list {//private data members: a pointer + size, or two pointerspublic: //constructors:constexpr initializer_list(const T*, const T*); //[first,last)constexpr initializer_list(const T*, int);//[first,first+size) //accessing the range constexpr int size() const; //number of elementsconstexpr const T* begin() const; //first element constexpr const T* end() const; //one-past-the-last element};
Put simply, initializer_list transforms a random number of values into a valid STL range by creating an array that contains copies of those values.
The Finishing Touches
Thus far, adding a sequence constructor to MyVector has involved the following:
- An initializer_list object silently intercepted an initializer list of the form ={5,6,7,8}; and transformed the values between the braces into a valid range.
- A sequence constructor initialized its object by accessing the range using the size(), begin() and end() member functions of initializer_list.
- Because initializer_list‘s member functions are declared constexpr, the compiler can optimize the sequence constructor considerably.
MyVector’s sequence constructor ultimately looks like this:
template class MyVector {public: //newly-added sequence constructor MyVector(initializer_list s) { n=s.size() elements = new T[n]; std::copy(s.begin(),s.end(),elements); }//...};
Having furnished MyVector with a sequence constructor, you can now initialize it as you would any standard C++09 container:
MyVector vi={1,3,5,7,11};