一致性初始化(uniform initialization)
C++11引入了“一致性初始化”概念,意思是面对任何初始化动作,可使用相同语法 { },进行一致性的初始化。
原理解析:当编译器看到大括号包起来的东西时,会生成一个initializer_list<T>(initializer_list它其实是关联一个array<T,n>),然后再调用构造函数时,一个个从array分解取出来然后调用构造函数,但是如果这个函数自身提供了initializer_list<T>参数类型的构造函数时,则不会分解而是直接传过去。
int i;//未初始化,如果直接使用会报错,error C4700: 使用了未初始化的局部变量“i”
int j{};
i = 0;
cout << "i=" << i << "j=" << j << endl;
int k(3.4); // warning C4244: “初始化”: 从“double”转换到“int”,可能丢失数据
//int m{ 3.4 }; //error C2397: 从“double”转换到“int”需要收缩转换,不允许窄化数据处理
cout << "k=" << k << endl;
int value[]{1,2,3,4,5,6,7,8,9};
cout << "sizeof(value)= " << sizeof(value) << endl;
int value2[] = { 1,2,3,4,5,6,7,8,9 };
cout << "sizeof(value2)= " << sizeof(value2) << endl;
vector<int> v1{ 1, 2, 3 };
std::initializer_list
定义于头文件 | ||
template< class T > | (C++11 起) | |
std::initializer_list<T>
类型对象是一个访问 const T
类型对象数组的轻量代理对象。std::initializer_list
对象在这些时候自动构造:
- 用花括号初始化器列表列表初始化一个对象,其中对应构造函数接受一个
std::initializer_list
参数 - 以花括号初始化器列表为赋值的右运算数,或函数调用参数,而对应的赋值运算符/函数接受
std::initializer_list
参数 - 绑定花括号初始化器列表到 auto ,包括在范围 for 循环中
initializer_list 可由一对指针或指针与其长度实现。复制一个 std::initializer_list
不会复制其底层对象。
底层数组不保证在原始 initializer_list 对象的生存期结束后继续存在。 std::initializer_list 的存储是未指定的(即它可以是自动、临时或静态只读内存,依赖场合)。 | (C++14 前) |
底层数组是 const T[N] 类型的临时数组,其中每个元素都从原始初始化器列表的对应元素复制初始化(除非窄化转换非法)。底层数组的生存期与任何其他临时对象相同,除了从数组初始化 initializer_list 对象会延长数组的生存期,恰如绑定引用到临时量(有例外,例如对于初始化非静态类成员)。底层数组可以分配在只读内存。 | (C++14 起) |
若声明了 | (C++17 起) |
整个测试程序如下:
#include <iostream>
#include <vector>
#include <initializer_list>
using namespace std;
template <class T>
struct S {
std::vector<T> v;
S(std::initializer_list<T> l) : v(l) {
std::cout << "constructed with a " << l.size() << "-element list\n";
}
void append(std::initializer_list<T> l) {
v.insert(v.end(), l.begin(), l.end());
}
std::pair<const T*, std::size_t> c_arr() const {
return{ &v[0], v.size() }; // 在 return 语句中复制列表初始化
}
};
/*
* initializer_list
*/
template <typename T>
void print(initializer_list<T> list)
{
for (auto p = list.begin(); p != list.end(); ++p)
{
cout << *p << endl;
}
}
/*
* 一致性初始化(uniform initialization)
* 实现思想:
* 当编译器看到大括号包起来的东西时,会生成一个initializer_list<T>(initializer_list它其实是关联一个array<T,n>),
* 然后再调用构造函数时,一个个从array分解取出来然后调用构造函数,但是如果这个函数自身提供了initializer_list<T>
* 参数类型的构造函数时,则不会分解而是直接传过去。
*/
int main()
{
int i;//未初始化,如果直接使用会报错,error C4700: 使用了未初始化的局部变量“i”
int j{};
i = 0;
cout << "i=" << i << "j=" << j << endl;
int k(3.4); // warning C4244: “初始化”: 从“double”转换到“int”,可能丢失数据
//int m{ 3.4 }; //error C2397: 从“double”转换到“int”需要收缩转换,不允许窄化数据处理
cout << "k=" << k << endl;
int value[]{1,2,3,4,5,6,7,8,9};
cout << "sizeof(value)= " << sizeof(value) << endl;
int value2[] = { 1,2,3,4,5,6,7,8,9 };
cout << "sizeof(value2)= " << sizeof(value2) << endl;
vector<int> v1{ 1, 2, 3 };
S<int> s = { 1, 2, 3, 4, 5 }; // 复制初始化
s.append({ 6, 7, 8 }); // 函数调用中的列表初始化
std::cout << "The vector size is now " << s.c_arr().second << " ints:\n";
print({ 1,2,3,4,5,6,7,8,9 });
return 0;
}
输出结果: