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

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;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值