【C++泛型编程】编译期型别判断(Type Traits)

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这个型别。

你可能感兴趣的:(编程,C++,struct,iterator,Class,reference)