可变参数模板的定义
可变参数模板是至少有一个参数宝的模板,参数包则是可以接受零个或者更多模板实参的模板形参,其格式如下:
template <class ...T> class classname;
template <class ...T> void func(T ...args);
其中T
为模板参数包,args
为函数参数包。
可变参数模板可以用任意数量的模板参数实例化:
template <class... T> class Myclass{};
Myclass<> t0; //T 不包含实参
Myclass<int> t1; //T 包含一个实参,类型为int
Myclass<int,float> t2; //T 包含两个实参,类型为int和float
//模板参数包必须是模板参数列表中的最后一个形参。
template <typename... T,typename U> struct Invalid; //错误
可变参数函数模板可以用任意数量的函数实参调用:
template <class... T> void func(T... args);
func(); //args不包含实参
func(1); //包含一个实参,类型为int
func(1,2.1); //包含两个实参,类型为int和double
//与类模板不同,函数模板参数包不必是模板参数列表中的最后一个,它可以在列表早于所有能从函数实参推导的参数出现
template <class... T,class U>
void valid(U,T...); //正确
valid(1.0,2,3,4); //推导U为double,T为{int,int,int}
包展开
包展开的场所不同,产生的逗号分隔列表种类不同:
- 函数实参列表
func(&args...); //展开成func(&E1,&E2,&E3)
func(++args...,n); //展开成func(++E1,++E2,++E3,n)
func(n,++args); //展开成func(n,++E1,++E2,++E3)
func(const_cast<const Args*>(&args)...); // func(const_cast<const E1*>(&X1), const_cast<const E2*>(&X2), const_cast<const E3*>(&X3))
func(h(args...) + args...); // 展开成 func(h(E1,E2,E3) + E1, h(E1,E2,E3) + E2, h(E1,E2,E3) + E3)
- 有括号初始化器
Class c1(&args...); // 调用 Class::Class(&E1, &E2, &E3)
Class c2 = Class(n, ++args...); // 调用 Class::Class(n, ++E1, ++E2, ++E3);
- 花括号环绕的初始化器
template <class... T> void func(T... args)
{
const int size=sizeof...(args);
int res[size]={args...};
}
- 模板实参列表
//包展开可以用于模板形参列表的任何位置,前提是模板拥有匹配展开的形参。
template <class A,class B,class... C> void func(A arg1,B arg2,C... arg3)
{
container<A,B,C...> t1; // 展开成 container<A,B,E1,E2,E3>
container<C...,A,B> t2; // 展开成 container<E1,E2,E3,A,B>
container<A,C...,B> t3; // 展开成 container<A,E1,E2,E3,B>
}
- 函数形参列表
template<typename ...Ts> void f(Ts...) {}
f('a', 1); // Ts... 展开成 void f(char, int)
f(0.1); // Ts... 展开成 void f(double)
- 模板形参列表
template <class ...T> class Myclass
{
template<T... Values> // 展开成无类型模板参数列表,例如 <int, char, int(&)[5]>
};
- Lambda捕获
template <class ...T>
void func(T... args){
auto g=[&,args...]{return h(args...);}
g();
}
- sizeof…运算符
- 基类指定符和成员初始化列表
template<class... Mixins>
class X : public Mixins... {
public:
X(const Mixins&... mixins) : Mixins(mixins)... { }
};
实例
#include <iostream>
using namespace std;
void print(){
cout<<endl;
}
template <class T> void print(const T& t){
cout<< t <<endl;
}
template <class First,class... Rest>void print(const First& first,const Rest&... rest){
cout<<first<<",";
print(rest);
}
int main()
{
print();
print(1);
print(10,20);
print(100,200,300);
print("first",2,"third",3.14159);
}
实现C
语言中的printf
函数:
#include <iostream>
void tprintf(const char* format) // 基函数
{
std::cout << format;
}
template<typename T, typename... Targs>
void tprintf(const char* format, T value, Targs... Fargs) // 递归变参数函数
{
for ( ; *format != '\0'; format++ ) {
if ( *format == '%' ) {
std::cout << value;
tprintf(format+1, Fargs...); // 递归调用
return;
}
std::cout << *format;
}
}
int main()
{
tprintf("% world% %\n","Hello",'!',123);
return 0;
}