可变参数模板使我们可以创建接受可变数量的参数的模板类和模板函数
创建可变参数模板,需要理解的几个要点
1 模板参数包
2 函数参数包
3 展开参数包
4 递归
模板和函数参数包
C++11提供了一个用省略号表示的元运算符,让我们可以声明表示模板参数包的标识符,模板参数包基本上是一个类型列表。同样,它让我们能够声明表示函数参数包的标识符,而函数参数包基本上就是一个值列表。其语法如下:
template<typename... Args>
void show_list(Args... args){...}
其中,Args是一个模板参数包,args是一个函数参数包,与其他参数名一样,可以将这些参数包的名称指定为任何符合c++标识符规则的名称。Args与任意数量的类型匹配。
对于show_list(),我们可以指定很多参数,例如
show_list(2,4,5,"ha");
展开参数包
但是函数怎么访问这些包的内容呢?首先 索引功能在这里不适用,即不能使用Args[2]来访问包中的第三个参数。相反,可以将省略号放在函数参数包名的右边,将参数包展开。例如,下面的代码
template<typename... Args>
void show_list1(Args... args){ show_list1(args...);}
这个函数有缺陷的地方,假设有如下调用:
show_list1(5,'a',0.3);
这就把这三个参数封装到args中。在该函数的内部,下面的调用:
show_list1(args...); 变成了 show_list1(5,'a',0.3);
这很明显 这是在套娃;
在可变参数函数模板中使用递归
虽然前面的递归让show_list1()成为有用的函数希望破灭,但是为正确的使用递归访问参数包内容提供了解决方案;这里的核心理念是:将参数包展开,对列表中第一项进行处理,再将余下的内容传递给递归调用,以此类推,直到列表为空。与常规递归一样,确保递归的终止很重要。这里的技巧是将模板头改为下面这样:
template<typename T,typename... Args>
void show_list3(T value,Args... args){ show_list1(args...);}
对上述定义,函数的第一个实参决定了T和value的值,而其他实参决定了Args和args的值。这让函数能够对value进行处理,如显示它。然后递归调用show_list3(),并以args...的方式将其他实参传递给他。每次调用都将显示一个值,并传递了缩短的列表,直到列表为空。
下面 给出可执行的例子
#include <string>
#include <iostream>
using namespace std;
void show_list(){}//递归到无参数的时候 使用这个函数
//这个函数是递归到省一个参数时
template<typename T>
void show_list(const T& value) {
cout << value << endl;
}
template<typename T ,typename...Args>
void show_list(const T& value, const Args&... args) {
cout << value << ",";
show_list(args...);
}
int main() {
int n = 5;
double x = 3.14;
string xa = "xa.first";
show_list(x * x, "!", xa);
return 0;
}
大家可以自己试一下。