一、需求引入
让我们先来看一个函数模板
template<typename T>
Array<T> operator+ (Array<T> const&, Array<T> const&);
这很好,但由于语言允许我们将一个 char 和一个 int 相加,我们十分希望诸如此类的混合操作 也能实施于 arrays 身上。这么一来我们就必须决定新版本的回返类型(return type)应该是什么:
template<typename T1, typename T2>
Array<???> operator+ (Array<T1> const&, Array<T2> const&);
问题是Array<???> 到底应该是什么类型呢?
promotion traits template 使我们能够以如下方式填充上述声明中的问号:
template<typename T1, typename T2>
Array<typename Promotion<T1, T2>::ResultT>
operator+ (Array<T1> const&, Array<T2> const&);
或使用如下方式:
template<typename T1, typename T2>
typename Promotion<Array<T1>, Array<T2> >::ResultT
operator+ (Array<T1> const&, Array<T2> const&);
此种想法在于为 template Promotion 提供大量特化版本,以创建出一个满足我们所需的 type function。另一个应用由 max() template 激发出来:当我们希望指出类型不同的两数值中的较大 者时,应该采用「较大」的那个类型(2个类型中更加强大的类型)
二、实现
第一步:声明typename Promotion主模板
由于template 并不存在真正的泛型定义。最好的选择是:别去定义 primary class template(主模 板):
template<typename T1, typename T2>
class Promotion;
第二步:定义一个具有在2个类型中选择某一个类型方法的模板
//主模板(未定义):根据第一个实参来决定:是选择第二个实参,还是选择第三个模板
template<bool C, typename Ta, typename Tb>
class IfThenElse;
// 局部特化: true 的话选择第二个实参
template<typename Ta, typename Tb>
class IfThenElse<true, Ta, Tb> {
public:
typedef Ta ResultT;
};
// 局部特化: false 的话选择第三个实参
template<typename Ta, typename Tb>
class IfThenElse<false, Ta, Tb> {
public:
typedef Tb ResultT;
};
第三步:定义第一步中声明的模板
template<typename T1, typename T2>
class Promotion {
public:
//typedef一个类型
typedef typename
IfThenElse<(sizeof(T1)>sizeof(T2)) , //第一个参数
T1, //第二个参数
typename IfThenElse<(sizeof(T1)<sizeof(T2)), T2, void >::ResultT //第三个参数
>::ResultT ResultT;
};
第四步:针对Promotion 进行一些局部特化
//两个参数相同的局部特化版本
template<typename T>
class Promotion<T,T> {
public:
typedef T ResultT;
};
第五步:针对普通类型的 全特化 版本
可以利用宏,减少源代码的数量
#define MK_PROMOTION(T1,T2,Tr) \
template<> class Promotion<T1, T2> { \
public: \
typedef Tr ResultT; \
}; \
template<> class Promotion<T2, T1> { \
public: \
typedef Tr ResultT; \
};
第六步:添加一些普通类型的全特化提升
MK_PROMOTION(bool, char, int)
MK_PROMOTION(bool, unsigned char, int)
MK_PROMOTION(bool, signed char, int)
//...
这种方式相当直截了当,却需要列举数十个可能组合。
第七步:为了一般类型提供提升的规则(除了基本类型和枚举类型之外)
以先前的 Array 为例:
template<typename T1, typename T2>
class Promotion<Array<T1>, Array<T2> > {
public:
typedef Array<typename Promotion<T1,T2>::ResultT> ResultT;
};
//针对array的 2个参数相同的 局部特化版本
template<typename T>
class Promotion<Array<T>, Array<T> > {
public:
typedef Array<typename Promotion<T,T>::ResultT> ResultT;
};
最后这个偏特化版本有若干特别值得注意的地方。 乍见之下, 好像先前针对类型一致 (identical types)而设计的局部特化版本(Promotion<T,T>)已经处理了这种情况。不幸的是,就特化程度而言,Promotion<T,T>和 Promotion<Array<T1>, Array<T2> >
是一样的。为避免选择 templates 时发生模棱两可(歧义)情况,我们增加了最后一个局部特化版本,它比前面2个局部特化版本更加特殊化。
当更多 types 被加入时,为了使 promotion(类型晋升)有意义,我们需要为 Promotion template 加入更多的全特化版本和局部特化版本。
三、使用
Promotion 的 使用方法在需求引入部分已经提到了