回顾一下模板

来源:互联网 发布:小米笔记本office软件 编辑:程序博客网 时间:2024/06/05 03:49
--------------------------------------------比特科技整理--------------------------------------------
  • 本节目标
  1. 泛型编程
  2. 模板函数&类模板
  3. 非类型模板参数&模板的模板参数
  4. 模板的特化
  5. 模板的分离编译

  • 概念
模板是泛型编程的基础。所谓泛型编程就是编写与类型无关的逻辑代码,是一种复用的方式。模板分为模板函数和模板类。

  • 模板函数
假设现在要实现一个比较两个数是否相等的重载函数。
boolIsEqual(intleft,intright){    returnleft==right;}boolIsEqual(conststring&left,conststring&right){    returnleft==right;}voidtest1(){    strings1("s1"),s2("s2");    cout<<IsEqual(s1,s2)<<endl;    cout<<IsEqual(1,1)<<endl;}...


如果还要比较int/char等等类型就都要分别实现一下,相似的代码重复度非常高。

函数模板格式:
template <class 形参名1class 形参名2, class 形参名n
  返回类型 函数名(参数列表)
{...}

模板形参的定义既可以使用class,也可以使用typename,含义是相同的。

模板函数登场,定义一个就搞定了。
template<typenameT>boolIsEqual(constT&left,constT&right){    returnleft==right;}voidtest1(){    strings1("s1"),s2("s2");    cout<<IsEqual(s1,s2)<<endl;    cout<<IsEqual(1,1)<<endl;}


从汇编的角度看模板函数的推演

  • 模板参数匹配及显示实例化
template<typenameT>boolIsEqual(constT&left,constT&right){    returnleft==right;}voidtest1(){    cout<<IsEqual(1,1)<<endl;    //cout<<IsEqual(1,1.2)<<endl;             //模板参数不匹配    cout<<IsEqual<int>(1,1.2)<<endl;        //显示实例化    cout<<IsEqual<double>(1,1.2)<<endl;     // 显示实例化}


  • 重载函数模板
boolIsEqual(constint&left,constint&right){    returnleft==right;}template<typenameT>boolIsEqual(constT&left,constT&right){    returnleft==right;}template<typenameT1,typenameT2>boolIsEqual(constT1&left,constT2&right){    returnleft==right;}voidtest1(){    cout<<IsEqual(1,1)<<endl;    cout<<IsEqual<int>(1,1)<<endl;    cout<<IsEqual(1,1.2)<<endl;}


  • 模板类
普通类顺序表的定义
typedefintDataType;//typedef char DataType;classSeqList{private:         DataType*_data;    int_size;    int_capacity;};template<typenameT>classSeqList{private:    T*_data;    int_size;    int_capacity;};


类模板的格式
template<class 形参名1class 形参名2, ...class 形参名n>  
 class 类名
 { ... };
  • 模板类
// 动态顺序表template<typenameT>classSeqList{public:    SeqList();    ~SeqList();private:    int_size;    int_capacity;    T*_data;};template<typenameT>SeqList<T>::SeqList()    :_size(0)    ,_capacity(10)    ,_data(newT[_capacity]){}template<typenameT>SeqList<T>::~SeqList(){    delete[]_data;}voidtest1(){    SeqList<int>sl1;    SeqList<double>sl2;}



  • 模板参数--实现容器适配器
template<typenameT>classSeqList{private:    int_size;    int_capacity;    T*_data;};// template <class T, class Container>template<classT,classContainer=SeqList<T> >//缺省参数classStack{public:    voidPush(constT&x);    voidPop();    constT&Top();    boolEmpty();private:    Container _con;};voidTest(){    Stack<int>s1;    Stack<int,SeqList<int>>s2;    //思考下面这种使用场景会怎样?    Stack<int,SeqList<char>>s3;}模板的模板参数--容器适配器template<typenameT>classSeqList{private:    int_size;    int_capacity;    T*_data;};// template <class T, template<class> class Container>template<classT,template<class>class Container=SeqList>//缺省参数classStack{public:    voidPush(constT&x);    voidPop();    constT&Top();    boolEmpty();private:    Container<T>_con;};voidTest(){    Stack<int>s1;    Stack<int,SeqList>s2;}


  • 非类型的类模板参数
// 静态顺序表//template<typename T, size_t MAX_SIZE>template<typenameT,size_tMAX_SIZE= 10>//带缺省模板参数classSeqList{public:    SeqList();private:    T_array[MAX_SIZE];    int_size;};template<typenameT,size_tMAX_SIZE>SeqList<T,MAX_SIZE>::SeqList()    :_size(0){}voidTest(){    SeqList<int>s1;    SeqList<int, 20>s2;}


  • 非类型的模板函数参数
template<classT,intvalue>T Add(constT&x){    returnx+value;}浮点数和类对象是不允许作为非类型模板参数的//template<class T, string name>template<classT,doubleMaxSize>classTest{private:    double_value;};


  • 类模板的特化
全特化
</pre><pre name="code" class="cpp">
template<typenameT>classSeqList{public:    SeqList();    ~SeqList();private:    int_size;    int_capacity;    T*_data;};template<typenameT>SeqList<T>::SeqList()    :_size(0)    ,_capacity(10)    ,_data(newT[_capacity]){    cout<<"SeqList<T>"<<endl;}template<typenameT>SeqList<T>::~SeqList(){    delete[]_data;}template<>classSeqList<int>{public:    SeqList(intcapacity);    ~SeqList();private:    int_size;    int_capacity;    int*_data;};//特化后定义成员函数不再需要模板形参SeqList<int>::SeqList(intcapacity)         :_size(0)         ,_capacity(capacity)         ,_data(newint[_capacity]){    cout<<"SeqList<int>"<<endl;}//特化后定义成员函数不再需要模板形参SeqList<int>::~SeqList(){    delete[]_data;}voidtest1(){    SeqList<double>sl2;    SeqList<int>sl1(2);}



  • 偏特化(局部特化)
template<typename T1,typename T2>classData{public:    Data();private:    T1_d1;    T2_d2;};template<typename T1,typename T2>Data<T1,T2>::Data(){    cout<<"Data<T1, T2>"<<endl;}//局部特化第二个参数template<typenameT1>classData<T1,int>{public:    Data();private:    T1_d1;    int_d2;};template<typenameT1>Data<T1,int>::Data(){    cout<<"Data<T1, int>"<<endl;}ps:下面的例子可以看出,偏特化并不仅仅是指特殊部分参数,而是针对模板参数更进一步的条件限制所设计出来的一个特化版本。//局部特化两个参数为指针类型template<typenameT1,typenameT2>classData<T1*,T2*>{public:    Data();private:    T1_d1;    T2_d2;    T1*_d3;    T2*_d4;};template<typenameT1,typenameT2>Data<T1*,T2*>::Data(){    cout<<"Data<T1*, T2*>"<<endl;}//局部特化两个参数为引用template<typenameT1,typenameT2>classData<T1&,T2&>{public:    Data(constT1&d1,constT2&d2);private:    constT1&_d1;    constT2&_d2;    T1*_d3;    T2*_d4;};template<typenameT1,typenameT2>Data<T1&,T2&>::Data(constT1&d1,constT2&d2)             :_d1(d1)             ,_d2(d2){    cout<<"Data<T1&, T2&>"<<endl;}voidtest2(){    Data<double,int>d1;    Data<int,double>d2;    Data<int*,int*>d3;    Data<int&,int&>d4(1, 2);}


模板的全特化和偏特化都是在已定义的模板基础之上,不能单独存在。

  • 模板的分离编译

解决办法:
  1. 在模板头文件 xxx.h 里面显示实例化->模板类的定义后面添加 templateclassSeqList<int>; 一般不推荐这种方法,一方面老编译器可能不支持,另一方面实例化依赖调用者。(不推荐)
  2. 将声明和定义放到一个文件 "xxx.hpp" 里面,推荐使用这种方法。

【分离编译的扩展阅读】
http://blog.csdn.net/pongba/article/details/19130

  • 模板总结
优点:
  1. 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生。
  2. 增强了代码的灵活性。
缺点:
  1. 模板让代码变得凌乱复杂,不易维护,编译代码时间变长。
  2. 出现模板编译错误时,错误信息非常凌乱,不易定位错误。



0 0