C++模板

2020-09-28 11:01:16

一、什麼是模板
模板是C++中自動生成程式碼的技術。

二、為什麼使用模板
問題:實現一個通用的排序演演算法。
C語言:通過回撥函數實現,使用者呼叫麻煩。
C++語言:函數過載,需要為多種型別實現一個第一版本,還會導致程式碼段增加。
C/C++語言:藉助宏函數實現,型別檢查不嚴格,頻繁使用還會增加程式碼段。
由於以上原因C++之父在C++中實現了模板技術,既能技術多種類也能兼顧嚴格的型別檢查,能讓程式設計師程式設計專注思考業務邏輯而不用關係資料型別。

三、函數模板
1、函數模板的定義
template <typename T1,typename T2,…>
T2 函數名(T1 a1,T2,a2)
{
T1 v1;
T2 v2 = x;
return v2;
}

可以使用任何識別符號作來型別引數,但使用T是俗成約定的。
typedef 也可以換成 class 它們沒有任何區別。
2、函數模板的使用
C++編譯器並不是把函數模板編譯成一個可以處理所有型別的實體,而是根據呼叫者提供的引數,生產不同的函數實體。

根據具體型別帶入函數模板產生函數實體的過程叫範例化。

模板是呼叫時才實體化:
自動範例化:根據呼叫者提供資料型別自動判斷出型別。
手動範例化:func<型別,…>(引數)
模板的型別引數,與函數的引數沒有關係時使用。

模板的引數型別也可以使用預設形參。
3、模板函數的範例化過程
第一個模板函數都會經歷二次編譯,第一次編譯是在範例化之前,檢查模板程式碼自身是否正確,第二編譯是在範例化時,把呼叫者提供的型別引數帶入模板中再次檢查模板程式碼。

第二次編譯才生成二進位制的函數指令,第一次編譯僅僅是在編譯器的記憶體產生一個用於描述模板的資料結構。

4、模板函數自動範例化的限制
1、函數引數與模板引數沒有關係。
2、返回值型別不能隱式推斷。

5、模板的特化
模板並不適合所有情況,這時可以給特殊型別實現一個正常的函數。
模板函數在範例化之前會先檢查有沒有正常版本的函數,如果有就不會再繼續範例化,因此模板函數與正常函數並不會衝突。

四、類別範本
1、類別範本的定義格式
template <typename M,typename R,typename A,typename O>
class Test
{
private:
M val;
public:
R func(A a)
{
O a;
}
};

2、類別範本的使用
模板類的型別引數不能隱式打斷,也就是不能自動範例化,必須顯式的指定型別引數。
類名<型別> 物件;

類別範本的使用分為三個步驟:
1、檢查類別範本的語法,如果合法則在編譯器生成一個類的資料結構。
2、將使用者提供的型別引數代入類別範本再次檢查語法,如果合法編譯器會將類別範本範例化,並生成類物件的建立指令。
3、執行類物件的建立指令,建立出類物件。
注意:對於類的成員函數,並不全部範例化,而是呼叫誰範例化誰(生成二進位制指令)。

3、類別範本的靜態成員
類中的成員要在類中宣告,類外定義(具有const屬性的外除),類別範本的靜態成員也一樣。
template
class Test
{
static int val1;
static T val2;
public:
};
templateint Test::val1 = value;
templateT Test:: val2 = value;

4、遞迴範例化
模板的引數可以是任何型別,只要該類提供了模板程式碼中所需要的功能。
類別範本範例化後已經是一種型別了,所以它也只可以當模板的引數,這種範例化叫遞迴範例化。

5、類別範本的區域性特化
當類的成員函數不能通用,需要對特殊型別實現一個特殊版本的成員函數,這叫類的區域性特化,必須要在類外實現。
template<> 返回值型別 類名<特殊型別>::函數名(參數列)
{

}

6、類別範本的全域性特化
要針對某種特殊型別對類實現一個特殊版本,這叫作類的全域性特化。
template <> class 類名<特殊型別>
{

};

7、類別範本的預設形參
類別範本的引數也可以設定預設引數,用法與函數模板一致(靠右)。