模板作为C++语言特性的一个重要组成部分,被广泛用在范式编程中,在标准库中经常可以看到一些非常让人拍案叫绝的模板技术。在课程中接触到这些技术,做个整理和总结。
一. variadic templates
实现这一特性的方法是通过递归算法,一次处理一个目标参数,直到处理到最后的模板参数作为递归基返回。
以标准库的hash函数为例
template<typename... Types>
size_t hash_all(const Types&... args)
{
size_t seed=0;
hash_val(seed,args...); //进入计算
return seed;
}
template<typename T,typename... Types>
void hash_val(size_t &seed,
const T& val,const Types&... args)
{
//处理第一个模板参数
hash_combine(seed,val);
//递归
hash_val(sed,args...);
}
//处理到最后一个参数
template<typename T>
void hash_val(size_t &seed,const T& val)
{
hash_combine(seed,val);
}
//对模板参数进行处理
#include <functional>
template<typename T>
void hash_combine(size_t &seed,const T &val)
{
seed^=std::hash<T>()(val)+0x9e3779b9
+(seed<<6)+(seed>>2);
}
二. tuple的参数处理
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;
};
tuple的设计是利用继承链的最低端,在构造函数中对它的直接基类进行初始化,而它的基类又对基类的直接基类进行初始化,不断递归,直到直接基类是个空类为止。
//以tuple(1,2.3,"hello")为例
tuple<int,float,string> t(1,2.3,"hello");
t.head() ; //1
t.tail(); //(2.3,"hello")
t.tail().head(); //2.3
三. type traits的设计
标准库为我们提供了很多的type traits的模板类型,我们可以用来初始化获得类型的相关信息。
以 is_void为例,用来判断是不是void类型,解决思路是把对象的一些其他类型去除再来判断是否为void
//去除 const 的属性
template<typename T>
struct remove_const
{
typedef T type;
};
template<typename T>
struct remove_const<T const>
{
typedef T type;
};
//去除 volatile 的属性
template<typename T>
struct remove_volatile
{
typedef T type;
};
template<typename T>
struct remove_volatile<T volatile>
{
typedef T type;
};
//去除 const volatile 的属性
template<typename T>
struct remove_cv
{
typedef typename remove_const<typename remove_volatile<T>::type>::type type;
};
template<typename>
struct __is_void_helper
:public false_type{};
template<>
struct __is_void_helper<void>
:public true_type{};
template<typename T>
//最后继承 false_type 或 true_type
struct is_void
:public __is_void_helper<typename remove_cv<T>::type>::type{};
运用到模板的特化解决问题,很多思路都是可以借鉴的