initializer_list
模板initializer_list
可以使用初始化列表语法将STL容器初始化为一系列值:
std::vector<double> payments {45.99, 39.23, 19.95, 89.01};
这将创建一个包含4个元素的容器,并使用列表中的4个值来初始化这些元素。
这之所以可行,是因为容器类现在包含将 initializer_list<T>
作为参数的构造函数。
因此上述声明与下面的代码等价:
std::vector<double> payments({45.99, 39.23, 19.95, 89.01});
如果类有接受 initializer_list
作为参数的构造函数,则使用语法{}将调用该构造函数。
所有 initializer_list
元素的类型都必须相同,编译器会进行必要的转换,但不能进行隐式的窄化转换。
std::vector<double> payments {45.99, 39.23, 19, 89}; /*ok*/
/*same as std::vector<double> payments {45.99, 39.23, 19.0, 89.0};*/
std::vector<int> payments {45, 39.23, 19, 89}; /*narrowing, compile-time error*/
使用initializer_list
要在代码中使用 initializer_list
对象,必须包含头文件 initializer_list
。
这个模板类包含成员函数 begin()
和 end()
,还包含成员函数 size()
,该函数返回元素数。
示例:
#include <iostream>
#include <initializer_list>
using namespace std;
double sum(initializer_list<double> il);
double average(const initializer_list<double> & ril);
int main() {
cout << "List 1: sum = " << sum({ 2,3,4 }) << ", ave = " << average({ 2,3,4 }) << '\n';
initializer_list<double> dl = { 1.1,2.2,3.3,4.4,5.5 };
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(initializer_list<double> il)
{
double tot = 0;
for (auto p = il.begin(); p != il.end(); p++)
tot += *p;
return tot;
}
double average(const initializer_list<double> & ril)
{
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;
}
可按值传递 initializer_list
对象,也可按引用传递。这种对象本身很小,通常是两个指针(一个指向开头,一个指向末尾的下一个元素),也可能是一个指针和一个表示元素数的整数,因此采用的传递方式不会带来重大的性能影响。STL按值传递它们。
函数参数可以是 initializer_list
字面量,如{2, 3, 4},也可以是 initializer_list
变量,如dl
。
initializer_list
的迭代器类型为 const
,因此不能修改initializer_list
中的值:
*dl.begin() = 2011.6; /*not allowed*/
可以将一个initializer_list
赋给另一个initializer_list
:
dl = { 16.0,25.0,36.0,40.0,64.0 }; /*allowed*/
initializer_list
的实现(背后主要由Array支持):
template<class _E>
class initializer_list
{
public:
typedef _E value_type;
typedef _E& reference;
typedef const _E& const_reference;
typedef size_t size_type;
typedef _E* iterator;
typedef const _E* const_iterator;
private:
iterator _M_array;
size_type _M_len;
/*The compiler can call a private constructor*/
constexpr initializer_list(const_iterator __a, size_type __l)
:_M_array(__a), _M_len(__l) { }
public:
constexpr initializer_list() noexcept:
_M_array(0), _M_len(0) { }
/*Number of elements.*/
constexpr size_type size() const noexcept { return _M_len; }
/*First element.*/
constexpr const_iterator begin() const noexcept { return _M_array; }
/*One pase the last element.*/
constexpr const_iterator end() const noexcept { return begin() + _M_len; }
}
The initializer_list object refers to the elements of this array without containing them: copying an initializer_list object produces another object referring to the same underlying elements, not to new copies of them.
The lifetime of this temporary array is the same as the initializer_list object.