- Overview
- Table of Contents
- Special Member Functions: Constructors, Destructors, and the Assignment Operator
- Operator Overloading
- Memory Management
- Templates
- Namespaces
- Time and Date Library
- Streams
- Object-Oriented Programming and Design Principles
- The Standard Template Library (STL) and Generic Programming
- Exception Handling
- Runtime Type Information (RTTI)
- Signal Processing
- Creating Persistent Objects
- Bit Fields
- New Cast Operators
- Environment Variables
- Variadic Functions
- Pointers to Functions
- Function Objects
- Pointers to Members
- Lock Files
- Design Patterns
- Dynamic Linking
- Tips and Techniques
- Five Things You Need to Know About C++11 Unions
- A Tour of C99
- A Tour of C1X
- C++0X: The New Face of Standard C++
- Reference Wrapper
- The Performance Technical Report
- auto for the People
- Ironing Templates' Syntactic Wrinkles
- Visual C++ Becomes ISO Compliant
- A Garbage Collector for C++
- C99 Core Features in C++0X
- The
shared_ptrClass - The shared_ptr Class, II
- Lambda Expressions and Closures, Part I
- Lambda Expressions and Closures, Part II
- Lambda Expressions and Closures, Part III
- The Type Traits Library, Part I
- The Type Traits Library, Part II
- The Type Traits Library, Part III
- finally Revisited
- The Any Library
- The nullptr Keyword Proposal
- Delegating Constructors
- The Explicit Conversion Operators Proposal
- Conditionally-Supported Behavior
- The weak ptr Class Template, Part I
- The weak ptr Class Template, Part II
- POD Types Revisited
- The rvalue Reference Proposal, Part I
- The rvalue Reference Proposal, Part II
- Proposal for New String Algorithms
- Concepts, Part I
- Concepts, Part II
- constexpr: Generalized Constant Expressions
- The constexpr Proposal: Constructors
- Strongly-Typed enum Types
- C++09: The Road Ahead
- C++09: Proposals by Statuses
- Changing Undefined Behavior to Diagnosable Errors
- New Character Types
- The __func__ Predeclared Identifier is Coming to C++
- Static Assertions
- The extern template Proposal
- Variadic Templates, Part I
- Variadic Templates, Part II
- Variadic Templates, Part III -- Critique
- Using unique_ptr, Part I
- Using unique_ptr, Part II
- Unrestricted Unions, Part I
- Unrestricted Unions, Part II
- Unrestricted Unions, Part III
- Types With No Linkage as Template Arguments
- New Initialization Syntax
- Initializer Lists and Sequence Constructors
- New Standard Library Algorithms
- Class Member Initializers
- Inheriting Constructors
- Introducing Attributes
- The Removal of Concepts From C++0x
- The Future of C++0x, Part I
- The Future of C++0X, Part II
- The Debate About Attributes, Part I
- The Debate About Attributes, Part II
- The Debate About Attributes, Part III
- The Debate About Attributes, Part IV
- Forward Declarations of Enum Types
- The SCARY Iterators Proposal, Part I
- The SCARY Iterators Proposal, Part II
- Heading for Deprecation: export, Exception Specification and register
- The Rejection of the Unified Function Syntax Proposal
- Rvalue References as Object Members
- FCD Approved
- The Debate on noexcept, Part I
- The Debate on noexcept, Part II
- The Debate on noexcept, Part III
- About-face -- [[Attributes]] to Be Replaced with Keywords
- Will Delegating Constructors Be Removed From C++0x?
- Rvalue References: Past, Present and Future, Part I
- Rvalue References: Past, Present and Future, Part II
- Rvalue References: Past, Present and Future, Part III
- A Move in the Right Direction, Part I
- A Move in the Right Direction, Part II
- New Keywords for Inheritance Control, Part I
- New Keywords for Inheritance Control, Part II
- FDIS Approved
- C++0x Concurrency
- The Reflecting Circle
- We Have Mail
- The Soapbox
- Numeric Types and Arithmetic
- Careers
- Locales and Internationalization
Initializer Lists and Sequence Constructors
Last updated Feb 27, 2009.
Initializer lists are another aspect of the new initialization syntax of C++09. An initializer list enables you to use a sequence of values wherever an initializer may appear. For example, you can initialize a vector with a random number of literal values. Behind the scenes, C++09 equips STL containers with a new type of a constructor that intercepts ={0,1} initializers. Find out all the details here.
What's An Initializer List?
An initializer list is a sequence of values packed in braces such as:
{0, 1, 3.14}
Using an initializer list to initialize a container seems simple and intuitive. However, C++03 won't let you do this:
vector <double> vd = {0, 1, 3.14}; //error in C++03
The problem is that the brace notation in C++03 is reserved for aggregates. Because vector isn't an aggregate, the code above is rejected. Replacing the braces with other forms of initialization won't work either:
vector <double> vd (0, 1, 3.14); //error in C++03 vector <double> vd = (0, 1, 3.14); //error in C++03
Instead, you need to default-constructor the vector, populating it subsequently with a sequence of push_back() calls:
vector <double> vd; vd.push_back(0); vd.push_back(1); vd.push_back(3.14);
Many C++ programmers have moaned about the lack of an intuitive means for initializing an object with a list of initializers. The standards committee also realized that C++ needed such a mechanism. The only problem was how to design an intuitive and consistent initialization notation without causing existing code to break. The chosen solution was a combination of two new concepts: a standard class template called std::initializer_list and a new type of constructors called sequence constructors.
Aggregates As Opposed To Classes with Constructors
As you already know, the existence of four different initialization notations in C++ confuses novices and complicates the design of generic code unduly. It was obvious that the new initialization list proposal would stick to a uniform syntax for all types: aggregates, built-in scalar types (int, char etc.), classes with constructors, and containers.
A C++09 compiler can tell whether an initializer in the form ={0,1,31.4} is an aggregate initializer, as in the following case:
double arr[]={0,1,31.4};
Or whether it's the new C++09 initializer list as in:
vector <double> vd = {0, 1, 3.14}; //C++09
The programmer isn't bothered by these technicalities; the use of an initializer list should "just work" in both cases, albeit with different semantics. Let's see how exactly it works.
The Solution: Sequence Constructors
A sequence constructor is one that takes a single argument of type std::initializer_list<T>. For example:
class C
{
C(initializer_list<int>); // construct from a sequence of ints
};
//usage
C c={1,12,23,455,0};
In essence, initializer_list<T> (defined in the new header <initializer_list>) transforms a sequence of values of type T into an array of T and uses that array to populate its object.
The initializer_list class has three member functions that allow access to the sequence:
template<class E> class initializer_list
{
//implementation (a pair of pointers or a pointer + length)
public:
constexpr initializer_list(const E*, const E*); // [first,last)
constexpr initializer_list(const E*, int); // [first, first+length)
constexpr int size() const; // no of elements
constexpr const T* begin() const; // first element
constexpr const T* end() const; // one-past-the-last element
};
C++09 already adds a sequence constructor to every STL container. The sequence constructor of std::vector for instance might look like this:
template<class T> class vector {
T* elem;
size_t n;
public:
vector (initializer_list<T> s) // C++09 sequence constructor. Constructs from a sequence of Ts
{
n= s.size();
reserve(n); //allocate raw storage for the initializer_list values
uninitialized_copy(s.begin(),s.end(),elem); //copy the values into the vector
}
// ... the rest as before
};
Consider our original example:
vector <double> vd = {0, 1, 3.14}; //C++09
In implementation in which vector doesn't define a sequence constructor (that is, C++03 and C++98 implementations), the declaration of vd will cause a compilation error. In C++09-compliant implementations the declaration of vd becomes valid. Under the hood, the initializer list {0, 1, 3.14} is interpreted as a temporary object constructed like this:
//for exposition only; C++09 code
double temp[] = {double(1), double(2), 3.14 } ;
initializer_list<double> tmp(temp, sizeof(temp)/sizeof(double)); //(first, length[
vector<double> v(tmp);
That is, a C++09 compiler constructs an array containing the initializers converted to the desired type (double in this example). This array is passed to vector's sequence constructor as an initializer_list object. The sequence constructor then copies the values from the array into its own buffer:
vector<initializer_list<double> tmp) {
reserve(temp.size());
uninitialized_fill(tmp.begin(),tmp.end(),elem);
}
Notice that the initializer_list object is passed by value. No need to worry about that since an initializer_list is a small object (typically containing only two pointers). Passing it by value enables implementations to inline most of the code.
Sequence Constructors and Aggregates
To avoid undesirable conversions and confusion between traditional K&R aggregate initializers and C++09 initializer lists, the compiler first checks whether vd has a declared constructor:
double vd[]={0,1,31.4}; //K&R aggregate initialization
vector <double> vd = {0, 1, 3.14}; //C++09
If a constructor is present the compiler operates according to the following rules:
- Look for a sequence constructor and use it if it's the best match; if there's no sequence constructor or if the sequence constructor doesn't match
- Look for a constructor (excluding sequence constructors) and use it if it matches the arguments provided; Otherwise
- Issue an error message
If vd has no declared constructor the compiler operates in this way:
- Check whether vd is an aggregate or a built-in type and treat the initializers between the braces as traditional POD initializers.
- If vd is neither an aggregate nor a built-in type, issue an error message.
Using these restrictions and precedence rules, the compiler can silently distinguish between traditional K&R brace initializers (which are still valid in C++09 of course) and the new C++09 sequence constructors.



