1.什么是可变参数模版
可变参数模版让您能够创建这样的模版函数和模版类,即可接受可变数量的参数。实例如下:
show_list(1,4.5);
show_list(1,3.4,'k',"abcd");
要创建可变参数模版,需要理解几个要点:
- 模版参数包;
- 函数参数包
- 展开参数包
- 递归
2.模版和函数参数包
先来看一个简单的模版函数,他显示一个只有一项的列表:
template<typename T>
void show_list(T value)
{
std::cout<< value <<std::endl;
}
在上述定义中有两个参数列表。模版参数列表只包含T,函数参数列表只包含value。C++11提供了一个用省略号表示的元运算符,让您能够声明表示模版参数包的标识符,模版参数包基本上是一个类型列表,函数参数包基本上是一个值列表。其语法如下:
template<typename... Args>
void show_list(Args... args)
{
...
}
其中,Args是模版参数包,args是函数参数包。有如下函数调用:
show_list('S',10,"test",3.5);
在这种情况下,参数包Args包含与函数调用中的参数匹配的类型即为:char,int,const char *和double。
3.展开参数包
函数如何访问这些包内容?索引功能在此处不适用,即您不能使用Args[1]来访问包中的第二个参数。但是,可将省略号放在函数参数包名的右边,将参数包展开。看如下有缺陷的代码:
template<typename... Args>
void show_list(Args... args)
{
show_list(args...);
}
假设有如下调用:
show_list(5,'L',0.5);
在该函数的内部,下面的调用:
show_list(args...)
将展开如下所示:
show_list(5,'L',0.5);
args被替换为三个存储在args中的值。表示法args…展开为一个参数列表。不幸的是,该函数调用与原始函数调用相同,因此他将使用相同的参数列表不断调用自己,导致无限递归。
4.在可变参数模版函数中使用递归
这里的核心理念是,将函数参数包展开,对列表中的第一项进行处理,再将剩余的内容传递给递归调用,以此类推,直到列表为空。与常规递归一样,确保递归终止很重要。这的技巧是将模版头改为如下所示:
template<typename T,typename...Args>
void show_list(T value,Args... args)
以下代码演示了这种技巧:
//定义无参数函数 终止递归调用
void show_list(){}
//定义变参模版函数
template<typename T,typename... Args>
void show_list(T value,Args... args)
{
std::cout<<value<<std::endl;
show_list(args...);
}
int main()
{
show_list(1,3.4,"ASD");
return 0;
}
第一个实参导致T为int,value为1,其他两种类型将放入Args(模版参数包)包中,而其他两个值将放入args(函数参数包)包中。在函数中使用cout显示value的值,然后再次调用show_list(args…),因为args…的展开作用,该调用等价于show_list(3.4,“ASD”),参数列表每次减少一项直至最终调用到show_list()退出递归。
当前版本按值传递一切,对于使用简单类型来说没什么问题,但对于大型类型来说效率很低。在可变参数模版中,可指定展开模式。为此,可将下述代码:
show_list(Args... args)
替换为:
show_list(const Args&... args)
这将对每个函数参数应用模式const&。即按引用传递。
C++可变参数模版详解
817

被折叠的 条评论
为什么被折叠?



