Here, because the vector element type is double, the list is type initializer_list
The usual list restrictions on narrowing apply:
std::vector
Here, the element type is int, and the implied conversion of 5.5 to int is not allowed.
It doesn’t make sense to provide an initializer_list constructor unless the class is meant to handle lists of varying sizes. For instance, you don’t want an initializer_list constructor for a class taking a fixed number of values. For example, the following declaration does not provide an initializer_list constructor for the three data members:
class Position
{
private:
int x;
int y;
int z;
public:
Position(int xx = 0, int yy = 0, int zz = 0)
: x(xx), y(yy), z(zz) {}
// no initializer_list constructor
...
};
This allows you to use the {} syntax with the Position(int,int,int) constructor:
Position A = {20, -3}; // uses Position(20,-3,0)
Using initializer_list
You can use initializer_list objects in your code by including the initializer_list header file. The template class has begin() and end() members, and you can use them to access list elements. It also has a size() member that returns the number of elements. Listing 16.22 shows a simple example using initializer_list. It requires a compiler that supports this C++11 feature.
Listing 16.22. ilist.cpp
// ilist.cpp -- use initializer_list (C++11 feature)
#include
#include
double sum(std::initializer_list
double average(const std::initializer_list
int main()
{
using std::cout;
cout << "List 1: sum = " << sum({2,3,4})
<<", ave = " << average({2,3,4}) << '\n';
std::initializer_list
cout << "List 2: sum = " << sum(dl)
<<", ave = " << average(dl) << '\n';
dl = {16.0, 25.0, 36.0, 40.0, 64.0};
cout << "List 3: sum = " << sum(dl)
<<", ave = " << average(dl) << '\n';
return 0;
}
double sum(std::initializer_list
{
double tot = 0;
for (auto p = il.begin(); p !=il.end(); p++)
tot += *p;
return tot;
}
double average(const std::initializer_list
{
double tot = 0;
int n = ril.size();
double ave = 0.0;
if (n > 0)
{
for (auto p = ril.begin(); p !=ril.end(); p++)
tot += *p;
ave = tot / n;
}
return ave;
}
Here’s a sample run:
List 1: sum = 9, ave = 3
List 2: sum = 16.5, ave = 3.3
List 3: sum = 181, ave = 36.2
Program Notes
You can pass an initializer_list object by value or by reference, as shown by sum() and average(). The object itself is small, typically two pointers (one to the beginning and one past end) or a pointer to the beginning and an integer representing the size, so the choice is not a major performance issue. (The STL passes them by value.)
The function argument can be a list literal, like {2,3,4}, or it can be a list variable, like dl.
The iterator types for initializer_list are const, so you can’t change the values in a list:
*dl.begin() = 2011.6; // not allowed
But, as Listing 16.22 shows, you can attach a list variable to a different list:
dl = {16.0, 25.0, 36.0, 40.0, 64.0}; // allowed
However, the intended use of the initializer_list class is to pass a list of values to a constructor or some other function.
Summary
C++ includes a powerful set of libraries that provide solutions to many common programming problems and the tools to simplify many more problems. The string class provides a convenient means to handle strings as objects as well as automatic memory management and a host of methods and functions for working with strings. For example, these methods and functions allow you to concatenate strings, insert one string into another, reverse a string, search a string for characters or substrings, and perform input and output operations.
Smart pointer templates such as auto_ptr and C++11’s shared_ptr and unique_ptr make it easier to manage memory allocated by new. If you use one of these smart pointers instead of a regular pointer to hold the address returned by new, you don’t have to remember to use the delete operator later. When the smart pointer object expires, its destructor calls the delete operator automatically.
The STL is a collection of container class templates, iterator class templates, function object templates, and algorithm function templates that feature a unified design based on generic programming principles. The algorithms use templates to make them generic in terms of type of stored object and an iterator interface to make them generic in terms of the type of container. Iterators are generalizations of pointers.