先看一个Demo:
累加序列:
template <typename T>
inline
T accum (T const* beg, T const* end)
{
T total = T(); // assume T() actually creates a zero value
while (beg != end) {
total += *beg;
++beg;
}
return total;
}
使用示例:
int main()
{
// create array of 5 integer values
int num[]={1,2,3,4,5};
// print average value
std::cout << "the average value of the integer values is "
<< accum(&num[0], &num[5]) / 5
<< '\n';
// create array of character values
char name[] = "templates";
int length = sizeof(name)-1;
// (try to) print average character value
std::cout << "the average value of the characters in \""
<< name << "\" is "
<< accum(&name[0], &name[length]) / length
<< '\n';
return 1;
}
结果:
显然char的类型有问题,变量total 应该转化为int
修改方案则是新加一个模版参数:
template <typename T,typename V=int>
inline
V accum (T const* beg, T const* end)
{
V total = V(); // assume T() actually creates a zero value
while (beg != end) {
total += *beg;
++beg;
}
return total;
}
同时添加了使用成本
accum<char,int>(&name[0], &name[length])
模版的trait力量:将动态模版参数定义到外部结构中
template<typename T>
class AccumulationTraits;
template<>
class AccumulationTraits<char> {
public:
typedef int AccT;
};
template<>
class AccumulationTraits<short> {
public:
typedef int AccT;
};
template<>
class AccumulationTraits<int> {
public:
typedef long AccT;
};
template<>
class AccumulationTraits<unsigned int> {
public:
typedef unsigned long AccT;
};
template<>
class AccumulationTraits<float> {
public:
typedef double AccT;
};
template <typename T>
inline
typename AccumulationTraits<T>::AccT accum (T const* beg,
T const* end)
{
// return type is traits of the element type
typedef typename AccumulationTraits<T>::AccT AccT;
AccT total = AccT(); // assume T() actually creates a zero value
while (beg != end) {
total += *beg;
++beg;
}
return total;
}
现在可以保持调用方式保持不变,通过trait来更改类型参数
accum(&name[0], &name[length])
现在结果是正确的
trait的默认值
trait类型的初始值用构造函数初始化可能会有问题,所以可以再次用trait来定义默认值
默认值方式:1.静态变量(只能整型数值和枚举),2.静态方法(推荐)
template<>
class AccumulationTraits<char> {
public:
typedef int AccT;
//static AccT const zero = 0;
static AccT zero() {
return 0;
}
};
更改后的初始化方式:
template <typename T>
inline
typename AccumulationTraits<T>::AccT accum (T const* beg,
T const* end)
{
// return type is traits of the element type
typedef typename AccumulationTraits<T>::AccT AccT;
AccT total = AccumulationTraits<T>::zero();
while (beg != end) {
total += *beg;
++beg;
}
return total;
}
This is the key of the traits concept: Traits provide an avenue to configure concrete elements (mostly types) for generic computations.
trait参数化
有时候我们想改变通过trait本身的默认模版参数,这样就需要对trait本事做一个参数封装
封装一个默认的模版参数
template <typename T,
typename AT = AccumulationTraits<T> >
class Accum {
public:
static typename AT::AccT accum (T const* beg, T const* end) {
typename AT::AccT total = AT::zero();
while (beg != end) {
total += *beg;
++beg;
}
return total;
}
};
1
现在之前的方法应该如下示例:
template <typename T>
inline
typename AccumulationTraits<T>::AccT accum (T const* beg,
T const* end)
{
return Accum<T>::accum(beg, end);
}
trait参数化
template <typename Traits, typename T>
inline
typename Traits::AccT accum (T const* beg, T const* end)
{
return Accum<T, Traits>::accum(beg, end);
}
Policy
Policy注重算法,如下示例:Policy是一个静态类,通过动态编译来计算
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;
}
};
不同Policy算法
class SumPolicy {
public:
template<typename T1, typename T2>
static void accumulate (T1& total, T const & value) {
total += value;
}
};
class MultPolicy {
public:
template<typename T1, typename T2>
static void accumulate (T1& total, T const& value) {
total *= value;
}
};
使用示例:
int main()
{
// create array of 5 integer values
int num[]={1,2,3,4,5};
// print product of all values
std::cout << "the product of the integer values is "
<< Accum<int,MultPolicy>::accum(&num[0], &num[5])
<< '\n';
}