trait和policy类
trait
先看下面代码:
//accumtraits.h
template <typename T>
class AccumulationTraits;
template <>
class AccumulationTraits<char>
{
public:
typedef int Acct;
static Acct const zero = 0;
};
template <>
class AccumulationTraits<int>
{
public:
typedef long Acct;
static Acct const zero = 0;
};
//accum.h
#include "accumtraits.h"
template <typename T>
inline typename AccumulationTraits::Acct accum(T const *beg, T const * end)
{
typedef typename AccumulationTraits<T>::Acct Acct;
Acct total = AccumulationTraits<T>::zero; // 关键点
while (beg != end)
{
total += *beg;
++beg;
}
return total;
}
上面代码中,accum是一个求和的函数模板,而关键点在于total这个变量的类型和zero的值,这些是和模板参数T相关的:例如当模板实参为int,那total类型应该取long;当模板实参为char,total类型应该取int。
trait有特征的意思,把所有的T相关特征封装起来(这里特征更多指的是属性),就成了trait类模板AcculationTraits<>。
policy
trait是把T相关属性封装起来的一种技巧,也可以把T相关行为封装起来,称作policy:
// accum.h
template <typename T, typename Policy = SumPolicy, typename Traits = AccumulationTraits<T> >
class Accum
{
public:
typedef typename Traits::Acct Acct;
static Acct accum(T const *beg, T const *end)
{
Acct total = Traits::zero();
while (beg != end)
{
Policy::accumulate(total, *beg);
++beg;
}
return total;
}
};
// sumpolicy.h
class SumPolicy
{
public:
template<typename T1, typename T2>
static void accumulate (T1& total, T2 const &value)
{
total += value;
}
};
上面代码把SumPolicy实现为普通类,而把accumulate实现为成员函数模板,当然也可以反过来。
// sumpolicy.h
template <typename T1, typename T2>
class SumPolicy
{
public:
static void accumulate (T1& total, T2 const &value)
{
total += value;
}
};
// accum.h
template <typename T,
template<typename, typename> class Policy = SumPolicy,
typename Traits = AccumulationTraits<T> >
class Accum
{
public:
typedef typename Traits::Acct Acct;
static Acct accum(T const *beg, T const *end)
{
Acct total = Traits::zero();
while (beg != end)
{
Policy<Acct, T>::accumulate(total, *beg);
++beg;
}
return total;
}
};
trait的应用——提取类型
一些情况下,模板参数之前是存在依赖关系的,换句话说,在编译期部分参数可以根据其它参数来确定。
如果我们想实现一个模板函数,计算容器中所有元素的和,那么可以这样定义:
template <typename T, typename C>
T sum_of_elements(C const& c)
{
}
显然,返回类型T是根据容器元素类型来决定的,标准容器都定义有value_type这个成员变量。于是,可以把返回类型这一特征提取出来,放在一个命名为ElementT的trait模板中:
template <typename C>
class ElementT
{
public;
typedef typename C::value_type Type;
};
// 可以利用特化进行一些特殊处理
template <typename>
class ElementT<vector<string> >
{
public:
typedef int Type;
}
template <typename C>
typename ElementT<C>::Type sum_of_elements(C const& c)
{
}