【C++】含有可变形参的函数和省略符形参(附代码)

《C++primer 第五版》P197

目录

含有可变形参的函数:    

省略符形参


含有可变形参的函数:

有时我们无法预知应该向函数传递几个实参,例如我们想要编写代码输出程序产生的错误信息,此时最好使用同一个函数实现该项功能。

C++11新标准,如果所有的实参类型相同,可以传递一个名为initializer_list的标准库类型。initializer_list是一种标准库类型,用于表示某种特定类型的值的数组,initializer_list类型定义在同名的头文件中#include<initializer_list>


                             initializer_list提供的操作:

  1. initializer_list<T> L;                       //默认初始化,为T类型的空列表
  2. initializer_list<T> L{a,b,c...};         //L的元素数量和初始值一样多,L的元素是对应初始值的副本,列表的中元素是const的,不能修改
  3. L2(L);L2=L;                             //  拷贝或赋值一个initializer_list对象不会拷贝列表中的元素;拷贝后,原始列表和副本共享元素
  4. L.size()                                         //列表中的元素数量
  5. L.begin()                                      //返回指向L中首元素的指针
  6. 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(...)。所以不能这么去理解

 

希望对你有帮助哦,如果有错误的地方,望指正。

 

 

 

 

 

 

 

 

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值