- 一个可变参数模板就是一个接受可变数目参数的模板函数或模板类
- 存在两种参数包
- 用省略号指出一个模板参数胡函数参数表示一个包
- class…或者typename…指出接下来的参数表示零个或多个类型的列表
- 一个类型名后跟一个省略号表示零个或多个给定类型的非(模板)类型参数列表
- 在函数参数列表中,如果一个参数的类型那个是一个模板参数包,那么此参数是一个函数参数包
template<typename T, typename Args...>
void foo(const T &t, const Args& ...rest);
sizeof()…运算符
- sizeof()…运算符可以得出包中元素个数,返回值是常量表达式
编写可变参数函数模板
- 当我们既不知道处理的实参的数目,也不知道他们的类型的时候,可变参数函数非常有用
- 可变参数函数通常是递归的
- 例子:
//为了终止递归,需要定一个非可变参数的print函数,它接受一个流和一个对象
template<typename T>
ostream &print(ostream &os, const T &t)
{
os << t;
}
//包中除了最后一个元素之外的其他元素都会调用这个版本的print
template<typename T,typename... Args>
ostream &print(ostream &os,const T &t, const Args&... rest)
{
os << t <<","; //打印第一个实参
return print(os,rest...);//递归调用
}
- 代码
return print(os,rest...);
将rest的第一个实参绑定到T,一次类推,直到只剩最后一个实参 - 对于对后一个调用,两个函数提供了同样好的匹配,但是非可变实参函数比可变实参函数更特例化
包扩展
- 对于一个参数包除了获取其大小外,只能对他扩展了
- 当扩展一个包时,还要提供用于每个扩展元素的模式
- 通过在模式右边放省略号(…)出发扩展操作
template<typename T,typename... Args>
ostream &print(ostream &os,const T &t, const Args&... rest)//扩展Args,扩展模式为const Args&
{
os << t <<",";
return print(os,rest...); //扩展rest,扩展模式为rest...
}
- 第一个扩展操作扩展模板参数包,将模式const Args &应用到模板参数包Args中的每个元素,此模式扩展结果是一个逗号分隔的零个或多个类型的列表,每个类型有类似const type &模式。
- 第二个扩展操作扩展函数参数包,模式是函数参数包的名字rest,此模式扩展出一个由包中元素组成的,逗号分隔的列表
理解包扩展
template<typename... Args>
ostream &erroMsg(ostream &os,const Args&...rest)
{
return print(os,debug_rep(rest)...);//将包rest扩展,扩展模式为debug_rep(rest)
}
- 扩展模式debug_rep(rest)表示我们希望对函数参数包rest中每个元素调用debug_rep,扩展结果是一个逗号分隔的debug_rep调用列表
- 扩展中的模式会独立地应用与包中每个元素
转发参数包
- 组合使用可变参数模板和forward机制实现其实参不变地传递给其它函数
- 可变参数函数通常将他们的参数转发给其他函数,这种函数通常具有一下形式:
//fun有一个或多个参数,每个参数都是一个模板参数类型的右值引用
template<typename... Args>
void fun(Args &&... args)//Args扩展为一个右值引用列表
{
//work的实参既扩展Args又扩展args
work(std::forward<Args>(args)...);
}