C++
大约 3 分钟
C++
目录
可变参数模板 Variadic Templates
本篇参考:
可变参数函数
三个点...
的写法以前就有,但不是在模板里
printf 源码
int __cdecl printf (
const char *fromat,
... // 可以接受任意变量
)
{
// ...
}
可变参数模板
可变参数模板 函数递归
例程 - print
/** 模板代码 */
void print()
{
}
template <typename T, typename... Types>
void print(const T& firstArg, const Types&... args) // 表示参数的类型和数目都可变
{
cout << firstArg << endl;
print(args...);
}
/** 使用代码 */
print(7.5, "hello", bitset<16>(377), 42);
/* 输出:
7.5
hello
0000000101111001(16bit来表示377)
42
*/
Q:
template <typename T, typename... Types>
void print(const T& firstArg, const Types&... args){/**/}
// 和
template <typename... Types>
void print(const Types&... args){/**/}
// 可以共存吗
// 若可,谁比较泛化、谁比较特化
A:
// 可以共存
// 优先使用比较特化的那个版本,即
template <typename T, typename... Types>
void print(const T& firstArg, const Types&... args){/**/}
// 的版本
原理
...
就是一个pack包
- 用於template parameters,就是template parameters pack(模板参数包)
- 用於function parameter types,就是function parameter types pack(函数参数类型包)
- 用於function parameters,就是function parameters pack(函数参数包)
可以帮助我们做递归,以上述例程为例:
(7.5, "hello", bitset<16>(377), 42)
传入后会被分割成两块firstArg = 7.5
,args = ("hello", bitset<16>(377), 42)
然后重复这个过程递归调用,当args为0时,就调用print()
的重载版本
优先级
类
class CustomerHash{
public:
std::size_t operator()(const Customer& c) const {
return hash_val(c.fname, c.lname, c.no) // 调用【版本1】(只有版本1符合)
}
};
可变参数模板函数的重载
// 【版本1】
template <typename... Type>
inline size_t hash_val(const Types&... arg){ // 接受一个参数
size_t seed = 0;
hash_val(seed, args...); // 调用【版本2】(版本1、2、3均符合)
return seed;
}
// 【版本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...); // 调用【版本2】,递归到最后调用【版本3】
}
// 【版本3】
template<typename T>
inline void hash_val(size_t& seed, const T& val) { // 接受两个参数
hash_combine(seed, val);
}
#include <functional>
template <typename T>
inline void hash_combine(size_t& seed, const T& val){
seed ^ = std:hash<T>O(val) + 0x9e3779b9
+ (seed<<6) +(seed>>2);
}
可变参数模板 类递归
例程 - tuple
tuple头文件
template<typename... Values> class tuple;
template<> class tuple<>{};
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...){} // initialization list【关键】抽出来的部分定义为成员变量,其他部分给父类
typename Head::type head(){ return m_head; }
inherited& tail(){ return *this; } // 返回指针
protected:
Head m_head;
};
调用代码
tuple<int, float, string> t(41, 6.3, "nico");
t.head(); // 获得41
t.tail().head(); // 6.3
应用
应用方向
可变参数模板主要用于递归
可以很方便地完成 recursive function call(递归函数调用)
在标准库中的使用
(详见C++11标准库一节)