c++11新特性:Variadic Templates

使用形式

可变参数模板(variadic template)为一个接受可变数目参数的模板函数或模板类。
用class…或typename…指出接下来的参数表示零个或多个类型的列表。
一个类型名后面跟一个省略号表示零个或多个给定类型的非类型参数的列表(可以是一个函数的实参列表).

1
2
3
4
5
6
7
8
void print(){
cout << "empty";
}
template<typename T, typename... Types>
void print(const T& firstArg, const Types&... args){
cout << firstArg;
print(args...);
}

注意在上面例子中,在函数形参输入是Types&… args,省略在前,而在函数内则是args…,省略在后。
上例会输出每一个参数,直到为空时输出empty。展开参数包的函数有两个,一个是递归函数,另外一个是递归终止函数,参数包args…在展开的过程中递归调用自己,每调用一次参数包中的参数就会少一个,直到所有的参数都展开为止,当没有参数时,则调用非模板函数print终止递归过程。
编译器从函数实参推断模板参数类型.对可变参数模板,编译器还会推断包中的参数数目.用sizeof…()可以获取模板参数包的参数个数和函数参数包的参数个数.

实例

可以方便使用递归调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <functional>
//4
template<typename T>
inline void hash_combine(size_t& seed, const T&val){
seed ^= std::hash<T>()(val) + 0x9e3779b9
+ (seed << 6) +(seed >> 2);
}
//3
template<typename T>
inline void hash_val(size_t& seed, const T&val){
hash_combine(seed, val);
}
//2
template<typename T, typename...Types>
inline void hash_val(size_t& seed, const T&val, const Types&...args){
hash_combine(seed, val);
hash_val(seed,args...);
}
//1
template<typename... Types>
inline size_t hash_val(const Types&...args){
size_t seed = 0;
hash_val(seed, args...);
return seed;
}
int main(){
size_t res = hash_val(1,3,3182UL);
cout << res;
return 0;
}

上面这段函数的调用顺序是1 -> 2 -> 3 -> 4。
下面还有一个经典的tuple例子:

对于递归继承,也可以使用可变模板参数实现。例如STL中的tuple:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
template<typename... values>class tuple;
template<>class tuple<>{};

template<typename Head, typename... Tail>
class tuple<Head, Tail...>:private tuple<Tail...>{
typedef tuple<Tail...> inherited;
public:
tuple(){}
tuple(Head v, Tail... vtail):
m_head(v),inherited(vtail...){}

Head head(){
return m_head;
}

inherited& tail(){
return *this;
}
protected:
Head m_head;
}