C++11 可变参数模板
作者:互联网
介绍
一个可变参数模板是一个接受可变数目参数的模板函数或模板类。可变数目的参数成为参数包。存在两种参数包:模板参数包 ,表示零个或多个模板参数;函数参数包,表示零个或多个函数参数。
用一个省略号来指出一个模板参数或函数参数表示一个包。在模板参数列表中,class…或typename…指出接下来的参数表示零个或多个类型的列表;一个类型名后面跟着的省略号表示零个或多个该给定类型的非类型参数的列表。在函数参数列表中,如果一个参数的类型是一个模板参数包,则此参数也是一个函数参数包。例如:
//Args是一个模板参数包;rest是一个函数参数包
//Args表示零个或多个模板类型参数
//rest表示零个或多个函数参数
template<typename T,typename...Args>
void f(const T &t,const Args&...rest);
上例中的f是一个可变参数函数模板,有一个名为T的类型参数和一个名为Args的模板参数包。这个包表示零个或多个额外的类型参数。f的函数参数列表包含一个const&类型的参数,指向T的类型,还包含一个名为rest的函数参数包,此包表示零个或多个函数参数。
编译器会从函数的实参推断模板参数类型。对于一个可变参数模板,编译器还会推断包中参数的数目。例如对于下面给定的调用:
int i = 0; double d = 3.14; string s = "how are you";
f(i,s,42,d);
f(s,42,"hi");
f(d,s);
f("hi");
编译器会实例化如下四个版本:
void f(const int&,const string&,const int&,const double&);
void f(const string&,const int&,const char[3]&);
void f(const double&,const string&);
void f(const char[3]&);
在每个实例中,T的第一个类型都从第一个实参类型推断出来。剩下的实参提供函数额外实参的数目和类型。
sizeof…运算符
当需要知道包中有多少元素时,可以使用sizeof…运算符。类似sizeof,sizeof…也返回一个常量表达式,而且不会对其实参求值:
template<typename...Args>
void g(Args...args) {
cout << sizeof...(Args) << endl;//类型参数的数目
cout << sizeof...(args) << endl;//函数参数的数目
}
编写可变参数函数模板
可变参数函数通常是递归的。第一步调用处理包中的第一个实参,然后用剩余实参调用自身。如下的print函数,每次递归调用将第二个参数打印到第一个实参表示的流中。为了终止递归,还需要定义一个非可变参数的print函数,它接受一个流和一个对象:
//用来终止递归并打印最后一个元素的函数
//此函数必须在可变参数版本的print定义之前声明
template<typename T>
void print(ostream& os, const T& t) {
os << t << endl;
}
//包中除最后一个元素之外的其他元素都会调用这个版本的print
template<typename T,typename...Args>
void print(ostream& os, const T& t, const Args&...rest) {
os << t << ' ';//打印第一个实参
print(os, rest...);//递归调用,打印其他实参
}
(在vs2019中,如果在作用域中没有找到终止递归的函数不会导致无限递归,而是在编译时直接报错)
对于print(cout, i, s,d, 42);第二个函数的递归执行如下
调用 | t | rest |
---|---|---|
print(cout, i, s,d, 42); | i | s,d,42 |
print(cout, s,d, 42); | s | d,42 |
print(cout, d, 42); | d | 42 |
print(cout, 42); //调用非可变参数版本 |
标签:11,const,零个,C++,函数参数,参数,void,模板 来源: https://blog.csdn.net/Rengachan/article/details/110099378