- 模板的神奇之处就在于我们可以针对多种类型对类和函数进行参数化,但有时候为了解决一些问题,我们需要引入较多的参数,这样就显得很麻烦?有什么好的解决方法呢? 这是有人会想,对一些额外的参数指定缺省值就行了啊,当然可以啊!但是过多的缺省值使我们的代码也会显的很麻烦,有时候可能会出现效率低下的问题。因此,我们引入了trait模板机制和policy类来解决这个问题。
- policy类和trait模板机制,是两种c++程序设计机制,它们有助于对某些额外参数的管理,在这里的额外参数是指:在具有工业强度的模板设计中所出现的参数。
现在让我看一个简单的例子:
template<typename T>
T Sum(const T* beg, const T* end) {
T sum = T();
while (beg != end)
{
sum += *beg;
++beg;
}
return sum;
}
这是一个简单的求和的模板例子,用T()初始化sum(额外的参数),我们心中所想是:sum应该是0,然后进行接下来的累加求和。对于int,double,float等等之类的某些内置类型来说,是没有问题的。但是对于字符char 就会出现问题,因为char的默认初始化不是0,而是空字符。还有一点需要注意,char的范围很小,一般情况下char是1字节的。所以对于以上问题,有什么解决方法吗?当然有啊! 这就利用到了trait模板。
template<typename T>
class Traits;
template<>
class Traits <short> {
public:
typedef int Type;
};
template<>
class Traits<int> {
public:
typedef int Type;
};
template<>
class Traits<char> {
public:
typedef int Type;
};
template<>
class Traits<float> {
public:
typedef double Type;
};
template<typename T>
T Sum(const T* beg, const T* end) {
typedef typename Traits<T>::Type Acct;
Acct sum = Acct();
while (beg != end)
{
sum += *beg;
++beg;
}
return sum;
}
现在就完美的解决了这个问题。怎么解决的呢?我们为刚才的每个T都关联一个类型,所关联的类型就是用来存储累加和的类型。这种关联可以看作类型T的一个特征,因此我们就把这个类型(Acct)成为T的trait。但是问题又来了,我们刚刚不是说,sum应该是0吗? 那么有什么方法让它直接是0呢?而不需要默认构造。当然有的,让我们看看下面这个例子。
template<typename Person>
void foot1(Person& person) {
person.foot();
}
template<typename Person1>
void foot2(Person1& person1) {
person1.foot();
}
template<typename T>
class Traits;
template<>
class Traits <short> {
public:
typedef int Type;
static const Type zero = 0;
};
template<>
class Traits<int> {
public:
typedef int Type;
static const Type zero = 0;
};
template<>
class Traits<char> {
public:
typedef int Type;
static const Type zero = 0;
};
template<typename T>
T Sum(const T* beg, const T* end) {
typedef typename Traits<T>::Type Acct;
Acct sum = Traits<T>::zero;
while (beg != end)
{
sum += *beg;
++beg;
}
return sum;
}
有些情况下,我们需要对trait进行改写,所以引入了参数化trait,参数化trait主要目的:添加一个具有缺省值的模板参数,而且该缺省值是由我们前面介绍的trait模板决定的。在这种具有缺省值的情况下,许多用户就可以不需要提供这个额外的模板实参。
template<typename T>
class Traits;
template<>
class Traits <short> {
public:
typedef int Type;
static const Type zero = 0;
};
template<>
class Traits<int> {
public:
typedef int Type;
static const Type zero = 0;
};
template<>
class Traits<char> {
public:
typedef int Type;
static const Type zero = 0;
};
template<typename T>
class TypeTraits {
public:
typedef unsigned Type;
static const Type zero = 0;
};
template<typename T,typename Type=TypeTraits<T> >
T Sum(const T* beg, const T* end) {
typedef typename Type::Type Acct;
Acct sum = Type::zero;
while (beg != end)
{
sum += *beg;
++beg;
}
return sum;
}
以上我们执行的都是累加求和运算,其实还可以存在很运算,比如累积,幂运算等等。有时候我们想把这个运算的接口分离出来,单独进行构造,因此我们就引出了policy类。
template<typename T>
class Traits;
template<>
class Traits <short> {
public:
typedef int Type;
static const Type zero = 0;
};
template<>
class Traits<int> {
public:
typedef int Type;
static const Type zero = 0;
};
template<>
class Traits<char> {
public:
typedef int Type;
static const Type zero = 0;
};
class SumPolicy {
public:
template<typename T,typename U>
static void policy(T& sum, const U& value) {
sum += value;
}
};
template<typename T >
T Sum(const T* beg, const T* end) {
typedef typename Traits<T>::Type Acct;
Acct sum = Traits<T>::zero;
while (beg != end)
{
SumPolicy::policy<Acct, T>(sum, *beg);
++beg;
}
return sum;
}
那么trait和policy区别在哪里呢?
- policy 注重行为,trait则注重类型。
- trait 表述了模板参数的一些自然额外属性。
- policy 表述了泛型函数和泛型类的一些可配置行为。
对于trait,我们将会发现下列事实:
- trait可以是fixed trait(不需要模板参数进行传递)。
- trait参数通常都具有很自然的缺省值。
- trait参数可以依赖一个或多个主参数。
对于policy,我们将会发现下列事实:
- policy参数不需要具有缺省值,而且通常都是显示指定这个参数。
- policy参数和属于同一个模板的其他模板参数往往是正交的。
- policy class 一般都哦包含了成员函数。