initializer_list是C++11提供的新类型,定义在头文件中。
用于表示某种特定类型的值的数组,和vector一样,initializer_list也是一种模板类型。
template< class T >
class initializer_list;
要介绍initializer_list的使用,有必要先谈一谈列表初始化。
C++11扩大了初始化列表的适用范围,使其可用于所有内置类型和用户定义的类型。无论是初始化对象还是某些时候为对象赋新值,都可以使用这样一组由花括号括起来的初始值了。使用初始化列表时,可添加=,也可不添加。
//定义一个变量并初始化
int units_sold=0;
int units_sold(0);
int units_sold={0}; //列表初始化
int units_sold{0}; //列表初始化
当初始化列表用于内置类型的变量时,这种初始化形式有一个重要特点:如果我们使用列表初始化值存在丢失信息的风险,则编译器将报错:
long double ld=3.1415926536;
int a={ld},b={ld}; //错误:转换未执行,因为存在丢失信息的风险
int c(ld),d=ld; //正确:转换执行,且确实丢失了部分值
列表初始化就谈到这里,接下来介绍initializer_list的使用
它提供的操作如下:
initializer_list<T> lst;
//默认初始化;T类型元素的空列表
initializer_list<T> lst{a,b,c...};
//lst的元素数量和初始值一样多;lst的元素是对应初始值的副本
lst2(lst)
lst2=lst
//拷贝或赋值一个initializer_list对象不会拷贝列表中的元素;拷贝后,原始列表和副本元素共享
lst.size() //列表中的元素数量
lst.begin() //返回指向lst中首元素的指针
lst.end() //返回指向lst中尾元素下一位置的指针
需要注意的是,initializer_list对象中的元素永远是常量值,我们无法改变initializer_list对象中元素的值。并且,拷贝或赋值一个initializer_list对象不会拷贝列表中的元素,其实只是引用而已,原始列表和副本共享元素。
和使用vector一样,我们也可以使用迭代器访问initializer_list里的元素
void error_msg(initializer_list<string> il)
{
for(auto beg=il.begin();beg!=il.end();++beg)
cout<<*beg<<" ";
cout<<endl;
}
如果想向initializer_list形参中传递一个值的序列,则必须把序列放在一对花括号内:
//expected和actual是string对象
if(expected != actual)
error_msg({"functionX",expectde,actual});
else
error_msg({"functionX","okay"});
说了这么多,那initializer_list到底有什么应用呢?
1.统一的初始化
*C++11扩大了初始化列表的适用范围,使其可用于所有内置类型和用户定义的类型。使用初始化列表时,可添加=,也可不添加Example:
class A
{
public:
A(int i,int j):x(i),y(j)
{
}
void fun()
{
cout<<x<<ends<<y<<endl;
}
private:
int x;
int y;
};
int main()
{
int x{1};
int y = {2};
int arr[]{1,2,3};
A a{1,2};
cout<<"x: "<<x<<endl;
cout<<"y: "<<y<<endl;
cout<<"int arr:"<<endl;
for(int i=0;i<3;i++)
{
cout<<"arr["<<i<<"]: "<<arr[i]<<ends;
}
cout<<endl;
cout<<"a :";
a.fun();
return 0;
}
运行结果
2.初始化列表语法的好处
*防止缩窄,即禁止将数值赋给无法存储它的数值变量,但允许更宽类型的转换
Example:
int main()
{
char c=200; //no warning
char c1{200};//Warning, narrowing conversion of '200' from 'int' to 'char' inside { }
double d{200};//ok
return 0;
}
3.std::initializer_list
STL容器提供了将initializer_list作为参数的构造函数
Example:
int main()
{
vector<int> vec{1,2,3,4};
for(int x:vec)
{
cout<<x<<ends;//1 2 3 4
}
return 0;
}
Tips:intializer_list还可以用作常规函数参数,此时需包含头文件(#include<initializer_list>)
这个模板类包含成员begin()和end(),可用于获悉列表的范围
Example:
void fun(initializer_list<int> il)
{
for(auto p=il.begin();p!=il.end();p++)
{
cout<<*p<<ends;
}
}
int main()
{
fun({1,2,3,4,5});
return 0;
}
Output:
1 2 3 4 5
初始化容器举例:
#include<string>
#include<map>
#include <initializer_list>
using std::string;
using std::map;
using std::pair;
using Pair = map<string, int>::value_type;
struct SessionHelper
{
SessionHelper(std::initializer_list<Pair> sessionList);
void insert(string sess, int i);
int findInt(string sess);
private:
map<string, int> session;
};
void SessionHelper::insert(string sess, int i)
{
session.insert(std::make_pair(sess, i));
}
SessionHelper::SessionHelper(std::initializer_list<Pair> sessionList)
{
session.insert(sessionList.begin(),sessionList.end());
}
int SessionHelper::findInt(string sess)
{
auto it = session.find(sess);
if(it != session.end())
return it->second;
return 0;
}