可变模板参数

侯捷老师的课程笔记

含义

类似下面的写法,在typename后面加了 … 表示一组东西,或者一包东西。
这一组东西,可以是任意类型。与c语言的的可变参数有点像。
使用variadic Templates 可以很方便的完成 recursive function call

示例

1
2
3
4
5
6
7
template<typename T,typename...Types>//任意类型
void print(const T& firstArg,const Types&...args)//任意个数
{
//sizeof...(args)
cout <<firstArg<<endl; //打印第一个参数
print(args...);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//结束递归使用
void print()
{
}

template<typename T,typename...Types>
void print(const T& firstArg,const Types&...args)
{
cout <<firstArg<<endl;
/*递归调用 一一分解参数,变为1+n的形式 直到把所有参数分解完,
然后调用上面的print()
*/
print(args...);
}
/*
example
1. print(123, others);
2. print(2.3 ,others);
3. print("abc",others);
4. print(bitset<16>(377),others(此时没有参数))
5. print();调用无形参的函数
*/
print(123,2.3,"abc",bitset<16>(377))

如果有下面的版本,那么可以编译通过吗?如果编译成功了会调用那一个?与上面的比较哪一个是特化?哪一个是范化?

1
2
3
4
5
template<typename...Types> 
void print(const Types&...args)
{
//todo do nothing
}

常见用法

万用哈希函数

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
31
32
33
34
35
36
37
38
#include<string>
#include<functional>
class Customer {
public:
std::string fname;
std::string lname;
std::string no;
}

class CustomerHash {
public:
std::size_t operator()(const Customer&c)const {
return hash_val(c.fname,c.lname.c.no);//调用函数1
}
// 1 首先进入这个函数
template<typename... Types>
inline std::size_t hash_val(const Types...args){
size_t seed = 0;
hash_val(seed,args...);//调用函数2 函数2是特化版本
return seed;
}
// 2
template<typename... Types>
inline void hash_val(std::szie_t& seed, const Types&...args){
hash_combine(seed,val);
hash_val(seed,args...);//递归调用函数2,直到剩余参数满足函数3,然后调用特化版本函数3结束递归调用
}
//3 auxiliary generic functions,用来结束递归。
template<typename T>
inline void hash_val(std::size_t& seed, const T& val){
hash_combine(seed,val);
}
//万用hash函数
template<typename T>
inline void hash_combine(std::size_t& seed, const T& val){
seed ^= std::hash<T>()(val) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
}

tuple实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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...){}

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