解释
C++03只有固定模板参数。C++11 加入新的表示法,允许任意个数、任意类别的模板参数,不必在定义时将参数的个数固定。
变长模板、变长参数是依靠C++11新引入的参数包的机制实现的。
参数包
-
一个模板形参包(template parameter pack)是一个接受零个或多个模板实参的模板形参。
template<class ... Types> struct Tuple { };
Tuple<> t0; // Types不含任何实参
Tuple<int> t1; // Types含有一个实参:int
Tuple<int, float> t2; // Types含有两个实参:int和float
Tuple<0> error; // 错误:0不是一个类型
-
一个函数形参包(function parameter pack)是一个接受零个或多个函数实参的函数形参
template<class ... Types> void f(Types... args);
f(); // OK:args不含有任何实参
f(1); // OK:args含有一个实参:int
f(2, 1.0); // OK:args含有两个实参int和double
-
一个形参包要么是一个模板形参包,要么是一个函数形参包。
-
一个包扩展(expansion)由一个模式(pattern)和一个省略号组成。包扩展的实例中一个列表中产生零个或多个模式的实例。模式的形式依赖于扩展所发生的上下文中
template <typename... TS> // typename... TS为模板形参包,TS为模式
static void MyPrint(const char* s, TS... args) // TS... args为函数形参包,args为模式
{
printf(s, args...);
}
解包
一个常用的技巧是:利用模板推导机制,每次从参数包里面取第一个元素,缩短参数包,直到包为空。
template <typename T>
void fun(const T& t){
cout << t << '\n';
}
template <typename T, typename ... Args>
void fun(const T& t, Args ... args){
cout << t << ',';
fun(args...);//递归解决,利用模板推导机制,每次取出第一个,缩短参数包的大小。
}
在C++17标准中,可以使用fold expression,更直接地表达,并且确保正序展开:
// C++17
template<typename T0, typename... T>
void printf(T0 t0, T... t) {
std::cout << t0 << std::endl;
if constexpr (sizeof...(t) > 0) printf(t...);
}
// C++11
#include <iostream>
template <typename T0>
void printf(T0 value){
std::cout << value << std::endl;
}
template <typename T, typename... Args>
void printf(T value, Args... args){
std::cout << value << std::endl;
printf(args...);
}
int main(){
printf(1, 2, "123", 1.1);
return 0;
}
关注公众号获取更多信息: