《C++primer 第五版》P197
目录
含有可变形参的函数:
有时我们无法预知应该向函数传递几个实参,例如我们想要编写代码输出程序产生的错误信息,此时最好使用同一个函数实现该项功能。
C++11新标准,如果所有的实参类型相同,可以传递一个名为initializer_list的标准库类型。initializer_list是一种标准库类型,用于表示某种特定类型的值的数组,initializer_list类型定义在同名的头文件中#include<initializer_list>
initializer_list提供的操作:
- initializer_list<T> L; //默认初始化,为T类型的空列表
- initializer_list<T> L{a,b,c...}; //L的元素数量和初始值一样多,L的元素是对应初始值的副本,列表的中元素是const的,不能修改
- L2(L);L2=L; // 拷贝或赋值一个initializer_list对象不会拷贝列表中的元素;拷贝后,原始列表和副本共享元素
- L.size() //列表中的元素数量
- L.begin() //返回指向L中首元素的指针
- L.end() //返回指向L中尾元素下一个位置的指针
- initializer_list是一种模板类型,定义initializer_list对象时,必须说明列表中所含元素的类型,例如:
- initializer_list<string> Li; //initializer_list 的元素类型是string
- initializer_list<char> Lo; //initializer_list 的元素类型是char型
- initializer_list<double> Lp; //initializer_list 的类型是double型
#include<iostream>
#include<initializer_list> //包含同名头文件
using namespace std;
void shareint(initializer_list<int> lint)
{
cout << "可变int参数模板" << endl;
cout << "size操作:"<< lint.size() << endl;
cout << "begin操作:"<< *(lint.begin()) << endl;
cout << "end操作:"<< *(lint.end() - 1) << endl;
initializer_list<int> lint2 = lint;
cout << "遍历:";
for (auto p = lint2.begin(); p != lint2.end(); ++p)
{
cout << *p << " "; // L2(L),L2 = L操作
}
cout << endl;
initializer_list<int> lint3{ 1,2,3,4,5 };
for (auto p = lint3.begin(); p != lint3.end(); ++p)
{
//*p=9; //不能对lint3的元素进行修改,为const
}
cout << endl;
}
void sharestring(initializer_list<string> lstr)
{
cout << "可变string参数模板" << endl;
cout << "size操作:" << lstr.size() << endl;
cout << "begin操作:" << *(lstr.begin()) << endl;
cout << "end操作:" << *(lstr.end() - 1) << endl;
cout << endl;
}
void shareint(int o,initializer_list<int> lint4,int i)
{
cout << "遍历:";
for (auto q = lint4.begin(); q != lint4.end(); ++q)
{
cout << *q << " ";
}
cout << endl;
}
int main()
{ //向含有可变参数模板传参时(调用时),实参要用{}花括号括起来,不会回认为传的普通参数
//shareint(5, 9); //错误:不存在从"int"转换到"std::initializer_list<int>"的适当构造函数
shareint({ 5, 9 }); //调用shareint(initializer_list<int> lint)
shareint({ 1,5,7,36 }); //调用shareint(initializer_list<int> lint)
shareint({ 11,2,23,663,48 }); //调用shareint(initializer_list<int> lint)
sharestring({ "ilol" }); //调用sharestring(initializer_list<string> lstr)
sharestring({ "ghj","ghj","uj" }); //调用sharestring(initializer_list<string> lstr)
//除了含有initializer_list形参外,还可以有其他形参,其他形参跟函数的普通调用一样,跟函数重载该调用哪个函数一样(配对的意思差不多)
shareint(8,{ 5,55,69,98,8 },9); //调用shareint(int o, initializer_list<int> lint4,int i)
return 0;
}
initializer_list 对象中的元素永远是常量(const),不能修改。
initializer_list<int> lint3{ 1,2,3,4,5 };
for (auto p = lint3.begin(); p != lint3.end(); ++p)
{
//*p=9; //不能对lint3的元素进行修改,p为const int* p
}
省略符形参
省略符形参是为了便于C++程序访问某些特殊的C代码而设置的,这些代码使用了名为varargs的C标准库功能,通常,省略符形参不应用于其他目的,C编译器文档会描述如何使用varargs。
省略符形参应该仅仅用于C和C++通用的类型,特别注意的是,大多数类类型的对象在传递个省略符形参时都无法正确拷贝
省略符形参只能出现在形参列表的最后一个位置,两种形式:
(1):void fun(数据类型 ,...)->如 void fun(int ,...);
(2):void fun(...);
(1)的形式是前面指定了部分形参的数据类型,给出的形参类型,调用时,实参会进行类型检查,省略的无须类型检查,第(1)种形式中,...前面的逗号可写可不写。
#include<iostream>
using namespace std;
void fun(...)
{
cout << "fun1" << endl;
}
void fun(int i,...) //void fun(int i...)
{
cout << "fun" << endl;
}
//此时fun函数形成重载,当没有fun(int i,...)时,fun(1,"5",'j'),fun(5, 3, 3)都调用fun(...)\
//就像当同时存在函数重载和函数模板时,先进行函数重载的精确匹配,若不能精确匹配函数重载函数,则再实例化函数模板,的意思类似(这样的方式去理解)。
//当有fun(int i,...)时,有给出参数的调用函数fun(1,"5",'j'),fun(5, 3, 3),将调用fun(int i,...)函数
//fun("j", 6)的情况,"j"是与fun(int i,...)的首形参是不匹配的,所以调用fun(...)\
//不匹配的话,也不可以认为首形参当不存在了,所以就调用fun(...),如果这样去认为的话,\
//fun("j", 6, 90)中的6就成首形参了,所以可以调用fun(int i,...),但结果是调用fun(...)。所以不能这么去理解
int main()
{
fun(); //fun1
fun(1,"5",'j'); //fun
fun(5, 3 ,3); //fun
fun("j", 6); //fun1
fun("j", 6, 90); //fun1
return 0;
}
/此时fun函数形成重载,当没有fun(int i,...)时,fun(1,"5",'j'),fun(5, 3, 3)都调用fun(...)\
//就像当同时存在函数重载和函数模板时,先进行函数重载的精确匹配,若不能精确匹配函数重载函数,则再实例化函数模板,的意思类似(这样的方式去理解)。
//当有fun(int i,...)时,有给出参数的调用函数fun(1,"5",'j'),fun(5, 3, 3),将调用fun(int i,...)函数
//fun("j", 6)的情况,"j"是与fun(int i,...)的首形参是不匹配的,所以调用fun(...)\
//不匹配的话,也不可以认为首形参当不存在了,所以就调用fun(...),如果这样去认为的话,\
//fun("j", 6, 90)中的6就成首形参了,所以可以调用fun(int i,...),但结果是调用fun(...)。所以不能这么去理解
希望对你有帮助哦,如果有错误的地方,望指正。