传统艺能😎
小编是双非本科大一菜鸟不赘述,欢迎米娜桑来指点江山哦(QQ:1319365055)
🎉🎉非科班转码社区诚邀您入驻🎉🎉
小伙伴们,打码路上一路向北,彼岸之前皆是疾苦
一个人的单打独斗不如一群人的砥砺前行
这是我和梦想合伙人组建的社区,诚邀各位有志之士的加入!!
社区用户好文均加精(“标兵”文章字数2000+加精,“达人”文章字数1500+加精)
直达: 社区链接点我
概念🤔
C++11 新增一员猛将就是可变参数模板,他可以允许可变参数的函数模板和类模板来作为参数,使得参数高度泛化。
在 C++11 之前类模板和函数模板中只能包含固定数量模板参数,而且也有可变参数的概念,比如 printf 函数就能够接收任意多个参数,但这是函数参数的可变参数,并不是模板的可变参数。可变模板参数无疑是一个巨大的改进,但由于可变参数模板比较抽象,因此使用起来并不会太简单。
模板定义🤔
函数的可变参数模板定义方式如下:
template<class …Args>
返回类型 函数名(Args… args)
{
//函数体
}
比如:
template<class ...Args>
void ShowList(Args... args)
{
}
注意这里的书写格式,模板参数Args前面有省略号,代表它是一个可变模板参数, 我们把带省略号的参数称为参数包 \color{red} {我们把带省略号的参数称为参数包} 我们把带省略号的参数称为参数包,参数包里面可以包含0到 N(N≥0) 个模板参数, 而 a r g s 则是一个函数形参参数包 \color{red} {而 args 则是一个函数形参参数包} 而args则是一个函数形参参数包。
模板参数包 Args 和函数形参参数包 args 的名字可以任意指定,并不是说必须叫做 Args 和 args 。
那么现在函数传参就可以实不同类型了:
int main()
{
ShowList();
ShowList(1);
ShowList(1, 'A');
ShowList(1, 'A', string("hello"));
return 0;
}
然后在函数模板中通过sizeof计算参数包中参数的个数:
template<class ...Args>
void ShowList(Args... args)
{
cout << sizeof...(args) << endl; //获取参数包中参数的个数
}
现在最大的难点就是我们无法直接获取参数包中的每个参数,语法并不支持使用 args[i] 的方式来获取参数包中的参数,只能通过展开参数包的方式来获取,这是使用可变参数模板的一个主要特点。
template<class ...Args>
void ShowList(Args... args)
{
//错误示例:
for (int i = 0; i < sizeof...(args); i++)
{
cout << args[i] << " "; //打印参数包中的每个参数
}
cout << endl;
}
参数包展开🤔
递归函开😎
该方法大概分为三步:
- 给函数模板增加一个模板参数,从接收的参数包中分离出一个参数出来
- 在函数模板中递归调用该函数模板,调用时传入剩下的参数包
- 继续递归,直到参数包中所有参数都被取出来
比如:
template<class T, class ...Args>
void ShowList(T value, Args... args)
{
cout << value << " "; //打印分离出的第一个参数
ShowList(args...); //继续递归调用
}
那么最后还有一个问题就是:递归展开该如何终止?
方法其实挺简单就是写一个无参的递归终止函数,该函数的函数名与展开函数的函数名相同,如果传入的参数包中参数个数是 0,那么就会匹配到这个无参递归终止函数,这样就结束了递归:
//递归终止函数
void ShowList