1. 程式人生 > >c++---非型別的類模板引數、類模板的特化、模板的分離編譯

c++---非型別的類模板引數、類模板的特化、模板的分離編譯

一. 非型別的類模板函式

在類的模板引數列表中,不一定是都是型別,或者介面卡,也可以是一個數。

//一般都使用int,用作規定大小
template <class T,size_t MAXSIZE>

具體使用:

template <class int, size_t MAX_SIZE = 10>
class SeqList
{
public:
    SeqList();
protected:
    T _array[MAX_SIZE];
    int _size;
};

int main()
{   
    SeqList<int,20> s;
    SeqList<int
> s1; //使用預設引數 }

   就像上面的程式碼,模板引數有兩個,一個是順序表中儲存資料的型別,另一個就是非型別的類模板引數,用於指定當前順序表所能儲存最大資料的個數。

除了模板類可以有非型別的模板引數,模板函式也是可以有非型別模板引數。

template <class T ,int value = 20>
T add(const T& x)
{
    return x + value;
}
int main()
{
    cout<<add<int>(2)<<endl;
    cout<<add<int
,30>(2)<<endl; return 0; }

   像上面的程式碼,非型別模板引數可以帶預設值,可以讓value為一個預設值,如果不傳第二個引數就預設為20,所以就有上面兩種寫法。我們若是不想使用預設值,就可以通過自己傳參的方式來改變這個值。

浮點數和類物件是不允許作為非型別模板引數的。

二. 類模板的特化

   什麼是特化呢?
   特化就是在寫好的模板類中,可能會有單獨的某種型別不能使用模板類中的定義,需要自己定義。
   就像是之前自己實現的vector模板類。在其中的拷貝構造,複製拷貝等操作,本來是可以使用memmove直接移動,可是考慮到string的深淺拷貝問題。我們就只能將所有元素一個元素一個元素賦值。就會導致效率降低,但是其他型別並沒有這種問題,所以我們應該讓string單獨出來自己實現自己的vector類。就有了這裡的特化。

全特化

一般格式就是這個樣子:注意在特化的類上面應該加著templlate<>,並且特化後的類的型別應該是加上型別後的。T1。

#include <iostream>
#include <string>
using namespace std;
template<class T>
class T1
{
public:
    T1();
    ~T1();
protected:
    T t;
};
template<>
class T1<string>
{
public:
    T1();
    ~T1();
protected:
    string t;
    string t1;
};
偏特化(區域性特化)

   特化不僅有全特化,還有偏特化。全特化是指對每一個引數都有確定的特化型別,特化後的類的引數都是確定的。偏特化是指對某個或某幾個引數進行限制。
這是一種偏特化的例子,將一個引數確定,另一個不確定:

#include <iostream>
#include <string>
using namespace std;
template<class T1,class T2>
class T
{
public:
    T()
    {
        cout << "<T1,T2>" << endl;
    }
protected:
    T1 t;
};

template<class T2>
class T<int,T2>
{
public:
    T()
    {
        cout << "<int ,T2>" << endl;
    }
protected:
    int t1;
    T2 t2;
};

int main()
{
    T<int,string> t1;
    T<string, int> t2;
    return 0;
}

這裡寫圖片描述
還有偏特化是將引數特化為指標型別與引用型別。

#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;
template<class T1,class T2>
class T
{
public:
    T()
    {
        cout << "<T1,T2>" << endl;
    }
protected:
    T1 t;
};

template<class T2>
class T<T1*,T2*>
{
public:
    T()
    {
        cout << "<T1* ,T2*>" << endl;
    }
protected:
    int t1;
    T2 t2;
};

int main()
{
    T<int,string> t1;
    T<string*, int*> t2;
    T<string*, int> t2;
    system("pause");
    return 0;
}

這裡寫圖片描述

三. 模板的分離編譯

在之前寫程式碼的正確格式應該是
這裡寫圖片描述
   但是如果寫了模板類,我們就不能使用這種格式來寫了,因為會出現連結錯誤。為什麼呢?之前說過,模板類與模板函式若是沒有例項化是不產生實際程式碼的,所以在程式碼連結過程中,例項化是在main.cpp中,會找不到函式的定義。
   所以我們在寫模板類模板函式時一般都要宣告與定義放在一起。

總結:

模板的優點:

  1. 模板複用了程式碼,節省資源,更快的迭代開發,C++標準模板庫產生
  2. 增強了程式碼的靈活性

缺點:

  1. 讓程式碼變得凌亂複雜,不易維護,編譯程式碼時間變長
  2. 出現模板編譯錯誤時,錯誤資訊非常凌亂,不易定位錯誤。