c++新特性之初始化列表
initializer Lists
用途:
用来设置初值
int i; //undefined
int j{} // 0
int *p;//uhdefined
int *q{} //nullptr
需要注意的 narrowing initializations
当有数据丢失的风险时会报错 或者 warining 下面是在gcc7.5.0上测试的结果
int x1(5.3);//OK
int x2 = 5.3;//OK
int x3{5.3}; //error: narrowing conversion of ‘5.2999999999999998e+0’ from ‘double’ to ‘int’ inside { } [-Wnarrowing]
int x4 = {5.3}; // error: narrowing conversion of ‘5.2999999999999998e+0’ from ‘double’ to ‘int’ inside { } [-Wnarrowing]
char c1 {7}; //OK
char c2{257}; //error: narrowing conversion of ‘257’ from ‘int’ to ‘char’ inside { } [-Wnarrowing]
std::vector<int> v1 {1,2,3,4,5};//OK
std::vector<int> v2{1,2.3,4,4.6};/ error: narrowing conversion of ‘2.2999999999999998e+0’ from ‘double’ to ‘int’ inside { } [-Wnarrowing]
c++11 提供了initializer_list<> 类来支撑上面的用法,我们也可以自己使用这个类,例如:
//tips
//标准库中的容器都有initializer_list为参赛的构造函数,故下面的
//initializer_list可以改为 deque,vector,list
auto print = [](std::initializer_list<int> vals)
{
for(auto p = vals.begin();p!=vals.end();++p)
{
std::cout<<*p<<std::endl;
}
};
print({1,2,3,4,5,6,7,13});
参数匹配规则:
- 如果有参数为initializer_list的函数,直接会调用对应参数为initializer_list的函数
- 如果没有参数为initializer_list的函数,则进行拆分initializer_list,去匹配有相同参数个数,相同参数类型的函数。
class P
{
public:
// fun1
P(int a, int b)
{
std::cout<< "P(int,int)"<<std::endl;
}
//fun2
P(std::initializer_list<int> initlist)
{
std::cout<<"P(initializer)"<<std::endl;
}
};
// fun1 与 fun2 同时存在的调用结果
P p(77, 5); // P(int,int)
P q{77, 5}; //P(initializer)
P r{77, 55, 26}; //P(initializer)
P s = {77, 5}; //P(initializer)
// 去掉构造函数fun2 只保留fun1
P p(77, 5); // P(int,int)
P q{77, 5}; //P(int,int)
P r{77, 55, 26}; //error: no matching function for call to ‘P::P(<brace-enclosed initializer list>)’
P s = {77, 5}; //P(int,int)
initializer_list 的实现原理
以下代码摘自 gcc 7.5.0
initializer_list的构造函数为 private故我们不能主动调用它,看注释可知这个构造函数是编译器可调用的。
故:当我们 使用大括号时 如{12,3,4,5},编译器会先生成一个数组,然后用数字的首地址,和size来构造initializer_list。
Tips
- const_iterator类型为const _E* 也就是元素的指针,它指向的是array的地址,故array 到initializer_list应该是浅拷贝。
- 标准库中用了大量的initializer_list,如容器的构造,插入,还有算法如:max({string(“abc”,string(“c”),string(“defg”)}),min({1,2,5,4,6,7,8})
//以下代码摘自 gcc 7.5.0 #include<initializer_list>
template<class _E>
class initializer_list
{
public:
typedef _E value_type;
typedef const _E& reference;
typedef const _E& const_reference;
typedef size_t size_type;
typedef const _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 past the last element.
constexpr const_iterator
end() const noexcept { return begin() + size(); }
};