1.编译期型别判断(Type Traits)
编译期型别判断犹如在执行期根据数值进行判断,那么型别判断在什么情况下使用呢?
举个例子:假设你想写个copying 算法:
template<typename InIt,typename OutIt> OutIt copy(InIt first,InIt last,OutIt result) { for(;first!=last;++first,++result) *result=*first; }
假设你要在一台多处理器的机器上开发程序,它有一个内置的函数BitBlast()只对基本型别和旧式结构有作用。你不能把该函数利用写非基本型别的copy函数。但是现在希望尽可能的利用BitBlast()来写上面的copy()算法。
void BitBlast(const void *src,void *test,size_t type);
如果下面两个条件之一符合就可以使用BitBlast()来完成copy动作:
a.InIt和OutIt是一般的指针吗?
b.InIt和OutIt所指的型别能进行位逐一拷贝吗?
故Type traits就用来对该型别进行判断。
下面这个例子用来判断型别T是否为指针:
template <typename T> class TypeTraits { private: template<class U> struct PointerTraits { enum{result=false}; typedef NullType PointeeType; //NullType是一种用于不能被使用情况下的占位型别 }; template<class U>struct PointerTraits<U*> //是上一个PointerTraits的偏特化,是一个针对任何指针型别的特化体,如果是指针就进入这个特化体 { enum{result=true}; typedef U PointeeType; }; public: enum{isPointer=PointerTraits<T>::result}; typedef PointerTraits<T>::PointeeType PointeeType; };
使用方法:
const bool iterIsPtr=TypeTraits<vector<int>::iterator>::isPointer;
TypeTraits还可以写出一个isReference常数和一个ReferencedType型别。对于一个reference type T,ReferencedType代表T所指向的型别。如果想判断一个指针是否指向成员函数,可以使用下面的偏特化:
template <typename T> class TypeTraits { private: template<class U> struct PToMTraits { enum{result=false}; }; template<class U,class V>struct PToMTraits<U V::*> //是上一个PToMTraits的偏特化{ enum{result=true}; }; public: enum{isMemberPointer=PToMTraits<T>::result}; };
2.基本型别判断
基本型别判断就是写一个TypeTraits<T>来判断T是否为基本型别包括void和所有数值型别(浮点数和整数)。它需要使用typelist型别列表的功能。
TL::IndexOf<T,TYPELIST_nn(typelist列表)>::value;
nn代表typelist列表中型别的个数。上面的代码返回型别T在typelist列表中的位置,从0开始算起,返回-1代表不存在该列表中。
例如:TL::IndexOf<T,TYPELIST_4(signed char,short int ,int ,long int)>::value;
TypeTraits对基本型别判断的定义如下:
template<typename T> class TypeTraits { ....as above... public: typedef TYPELIST_4(unsigned char, unsigned short int, unsigned int, unsigned long int) StdUnsignedInts; typedef TYPELIST_4(signed char, short int, int, long int) StdSignedInts; typedef TYPELIST_3(bool, char, wchar_t) StdOtherInts; typedef TYPELIST_3(float, double, long double) StdFloats; enum { isStdUnsignedInt = TL::IndexOf< T,StdUnsignedInts>::value >= 0 }; enum { isStdSignedInt = TL::IndexOf< T,StdSignedInts>::value >= 0 }; enum { isStdIntegral = isStdUnsignedInt || isStdSignedInt || TL::IndexOf< T,StdOtherInts>::value >= 0 }; enum { isStdFloat = TL::IndexOf< T,StdFloats>::value >= 0 }; enum { isStdArith = isStdIntegral || isStdFloat }; enum { isStdFundamental = isStdArith || isStdFloat || isVoid }; ...... }
3.参数传递型别优化
给定任何一个型别,我们怎么样确定以什么样的形参传人参数T给函数呢?是通过引用呢还是直接传值?
一般而言对于精巧型(有构造函数和析构函数额外调用动作)采用引用传参数,对于纯量型(数值型别,枚举型别,指针,指向成员的指针)采用直接传值的方式。
C++不允许有reference to references,如T是一个引用,别在它前面再加一层reference.我们把优化的参数型别称为:ParameterType
算法流程如下:
if(T是某型别的reference)
ParameterType就是T
else
{
if(T是纯量型)
ParameterType就是T
else
ParameterType就是T&
}
具体代码如下:
template<typename T> { ....as above... public: typedef Select<isStdArith||isPointer||isMemberPointer,T,ReferenceType&>::Result ParameterType; };
如果对枚举类型通过value传参上面的方案会参数错误。以为无法判别enum这个型别。