类模板以及其中的traits技术和type classification技术

来源:互联网 发布:淘宝这那样下架商品 编辑:程序博客网 时间:2024/06/01 09:59

1. 类模板相关概念

类模板用来描述一系列具有相同行为的类。一般有如下的形式:

template<class T, class U>class A{public:A(){ cout<<"Primary template\n";}private:    T t;    U u; };

如上所示的类模板我们一般称之为主类模板

实例化后的类模板称之为特化模板类,当我们全部的模板类型时,如下全部给定了T和U的类型时,,

template<>class A<int, int>{public:   A() { cout <<"<int, int> Fully specialization\n"; }private:   int t;   int u;  };
这称之为完全特化。当部分指定了类模板的参数类型时,称之为偏特化,如下所示,

template<class T>class A<T, T>{public:    A() { cout <<"<T,T> partial specialization\n";}private:    T t;    T u;};
当我们由一个类模板创建实例对象时,创建对象采用的模板类的匹配顺序为完全特化模板类-->偏特化模板类-->主类模板,示例如下:

#include <iostream>using namespace std;template<class T, class U>class A{public:    A(){ cout<<"Primary template\n";}private:    T t;    U u;};template<>class A<int, int>{public:  A() { cout <<"<int, int> Fully specialization\n"; }private:  int t;  int u;};/* *template<> *class A<int, float> *{ *public: *  A() { cout <<"<int, float> Fully specialization\n"; } *}; */template<class T, class U>class A<T*, U>{public:    A() { cout <<"<T*,U> partial specialization\n";}private:    T t;    U u;};template<class T>class A<T, T>{public:    A() { cout <<"<T,T> partial specialization\n";}private:    T t;    T u;};template<class U>class A<int, U>{public:    A() { cout <<"<int,U> partial specialization\n";}private:    int t;    U u;};int main(){    A<char,int> a1;    A<char*,int> a2;    A<float,float> a3;    A<int, float> a4;    A<int, int> a5;    return 0;}输出:Primary template<T*,U> partial specialization<T,T> partial specialization<int,U> partial specialization<int, int> Fully specialization

从上面的代码我们发现,采用不同的参数实例化出来的类具有不同的特征,但是他们可以有相同的接口,利用这一点,我们可以将不同数据类型的特征封装在一个类模板中,程序其它模块可以使用这个类模板的接口,获得每个数据类型的特征信息。这就是所谓的Traits技术

2. Traits技术

Ttraits在中文中称之为特性,Traits技术以一个统一的编程接口,描述各个数据类型的基本特征。例如,float和double能够表示的最小正数一般定义为常量FLT_EPSILON和DBL_EPSILON. 如果我们在一个数值库中分别要用到float和double, 在需要获得某个变量的特性时都要检查该变量的类型,非常麻烦。如果采用Traits技术,我们则可以用统一的接口来获取这些差异化的特性。

例如:

#include <iostream>#include <float.h>using namespace std;template <typename numT>struct fp_traits { };template<>struct fp_traits<float> {    typedef float fp_type;    enum { max_exponent = FLT_MAX_EXP };    static inline fp_type epsilon()    {        return FLT_EPSILON;    }};template<>struct fp_traits<double> {    typedef double fp_type;    enum { max_exponent = DBL_MAX_EXP };    static inline fp_type epsilon()    {        return DBL_EPSILON;    }};template <typename numT>class matrix {public:    typedef numT num_type;    typedef fp_traits<num_type> num_type_info;    inline num_type epsilon()    {        return num_type_info::epsilon();    }    //...};int main(){    matrix <float>  fm;    matrix <double> dm;    cout << "float  matrix: " << fm.epsilon() << endl;    cout << "double matrix: " << dm.epsilon() << endl;}

3. type classification技术

根据C++专家Water E.Brown的说法,C++中一般有如下14种类型:

template <class T> struct is_void;template <class T> struct is_null_pointer; //<- arrived in C++11 (std::nullptr_t)template <class T> struct is_integral;template <class T> struct is_floating_point;template <class T> struct is_array;template <class T> struct is_pointer;template <class T> struct is_lvalue_reference;template <class T> struct is_rvalue_reference;template <class T> struct is_member_object_pointer;template <class T> struct is_member_function_pointer;template <class T> struct is_enum;template <class T> struct is_union;template <class T> struct is_class;template <class T> struct is_function;
但是C++中和类型相关的运算符仅有sizeof, dynamic_cast, typeid等,他们在获取C++类型信息时非常有限,正是因为如此,我们可以基于类模板特化技术,设计专门的类模板来提供所需的信息,这种方法为类型分类(type classification)技术

设想有一个这样的任务:模板参数T可能是指针类型,引用类型或者数组(包括vector)中的某一种,我们需要判断T究竟是哪一个。如果是指针类型,需要知道该指针所指的类型,我们称为baseT,还需要该类型最底层的类型是哪个C++类型,我们称为bottomT; 比如对于指针类型int**, baseT为int *;bottomT为int; 对于数组类型,我们还希望可以获得其维数

下面的示例代码利用type classification技术很好的解决了这一问题:

#include <iostream>#include <vector>using namespace std;template<typename T>class TypeInfo {public:    enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 0 };    enum { Dim = 0 };    typedef T baseT;    typedef T bottomT;};template<typename T>class TypeInfo<T*> {public:    enum { IsPtrT = 1, IsRefT = 0, IsArrayT = 0 };    enum { Dim = 0 };    typedef T baseT;    typedef typename TypeInfo<T>::bottomT bottomT;};template<typename T>class TypeInfo<T&> {public:    enum { IsPtrT = 0, IsRefT = 1, IsArrayT = 0 };    enum { Dim = 0 };    typedef T baseT;    typedef typename TypeInfo<T>::bottomT bottomT;};template<typename T, size_t N>class TypeInfo <T[N]> {public:    enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 1 };    enum { Dim = 1 + TypeInfo<T>::Dim };    typedef T baseT;    typedef typename TypeInfo<T>::bottomT bottomT;};template<typename T, size_t N>class TypeInfo <T(*)[N]> {public:    enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 1 };    enum { Dim = 2 + TypeInfo<T>::Dim };    typedef T baseT;    typedef typename TypeInfo<T>::bottomT bottomT;};template<typename T>class TypeInfo <std::vector<T> > {public:    enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 1 };    enum { Dim = 1 + TypeInfo<T>::Dim };    typedef T baseT;    typedef typename TypeInfo<T>::bottomT bottomT;};template<typename T>size_t dims(T& a){    return TypeInfo<T>::Dim;}int main(){    TypeInfo<int** >::bottomT  x = 100;    typedef int* arrayType[100];    TypeInfo< arrayType >::bottomT  y = 200;    cout << x << " " << y << endl;    cout << TypeInfo<int[3]>::Dim << endl;    cout << TypeInfo<int[3][4]>::Dim << endl;    int array1[5][6];    int array2[5][6][7];    vector<int (*)[6][7]> array3;    cout << dims(array1) << endl;    cout << dims(array2) << endl;    cout << dims(array3) << endl;    cout << TypeInfo<vector<int[3][4]> >::Dim << endl;    cout << TypeInfo<vector<vector<int[3][4]> > >::Dim << endl;}



原创粉丝点击