模板是實作泛型編程的基礎,泛型編程即指撰寫與型別無關的邏輯代碼,是實作復用的一種手段,
模板可分為:函式模板,類模板
函式模板
概念
函式模板代表了一個函式族,該函式模板與型別無關,在使用時被引數化,根據實參型別產生函式的特定型別版本,
函式模板格式
template<typename T1,typename T2,……,typename Tn>
回傳值型別 函式名(形參串列){函式體}
如:
template<typename T>
void Swap(T& left,T& right){
T tmp = left;
left = right;
right = tmp;
}//一個可以實作交換功能的函式模板
【Note】: typename也可以用class代替
函式模板的原理
函式模板是編譯器產生特定具體型別函式的模具,本身并不是函式!
在編譯器編譯階段,當需要使用函式模板產生特定型別的函式時,編譯器會通過對實參型別的推演,確定傳入型別T,然后產生一份專門處理T型別的函式,
如:
double a = 3.14, b = 6.28;
int x = 1,y = 2;
char r = 'a', t = 'v';
Swap(a,b);
Swap(x,y);
Swap(r,t);
因為代碼里存在Swap的函式模板,三次呼叫傳入不同型別的資料,編譯器在階段推斷出每次傳入資料的型別,分別產生各自對應的函式,
上述代碼在編譯階段會多出3個函式:
void Swap(double& left,double& right){
T tmp = left;
left = right;
right = tmp;
}
void Swap(int& left,int& right){
int tmp = left;
left = right;
right = tmp;
}
void Swap(char& left,char& right){
char tmp = left;
left = right;
right = tmp;
}
這三個函式分別對應三次Swap函式的呼叫,我們只寫了一個函式模板,但最終代碼中會不同型別實參傳入,導致多出很多份函式,也就是說,使用模板的代碼,存在代碼膨脹的問題,
但在下認為不用函式模板,實作功能相同針對不同型別資料的函式,我們似乎只能通過函式多載實作,還是要寫很多函式,而模板的使用使得開發者免于去不斷重復撰寫功能相同,型別不同的函式,一定程度上減少了對于開發者來說意義不大但不可避免的低效作業內容,提高了作業效率,即便使用模板的代碼存在膨脹問題,似乎也只會膨脹到不用模板的地步,這也不是不可接受的問題,
函式模板的實體化
編譯器通過推斷傳入實參型別,針對不同型別產生對應函式的程序,稱為函式模板的實體化,模板實體化可分為:隱式實體化與顯示實體化
隱式實體化
隱式實體化即指開發者不告訴編譯器傳入實參的型別,讓編譯器自己根據傳入實參的型別推演自己該產生哪種函式,如下,我們并不告訴編譯器傳入實參是什么型別,
template<typename T>
void Swap(T& left,T& right){
T tmp = left;
left = right;
right = tmp;
}//一個可以實作交換功能的函式模板
int main(){
double a = 3.14, b = 6.28;
Swap(a,b);//隱式實體化
return 0;
}
顯式實體化
顯示實體化,我們只需在函式名的<>填入實參型別
如:
Swap<double>(a,b);//顯式實體化
個人覺得我們在使用函式模板時應當使用顯式實體化,方便自己把握自己的代碼,也方便他人閱讀,
模板引數的匹配原則
一般來說,當可以完成一個功能的非模板函式和模板函式均存在,存在一個策略幫助編譯器決定采用哪種方式定義的函式,
大白話說就是,現在有很多種函式都可以完成指定功能,這一大堆函式里有的函式編譯器什么也不需要做,它與被調函式引數串列完全匹配;有的需要隱式型別轉換;有的存在開發者指定的型別轉換,這時想完成一個功能就有了很多種選擇,為了結果盡量不出錯,避免編譯器左右橫跳,存在一個選擇策略,幫助編譯器選擇被調函式,
調選擇策略如下(優先級從高到底向下排列):
1.完全匹配:函式模板與非模板函式同時存在且均可以完成指定功能,型別不沖突(優先使用非模板函式)
2.提升轉換(char與short自動轉換int,flaot自動轉換為double)
3.標準轉換(int轉char,long轉double)
4.用戶定義的轉換,如類宣告中定義的轉換
模板的局限性
假設有如下模板函式:
template<typename T>
void f(T a,T b){
//函式體
}
一般來說,函式內中會存在一些操作,
如:
a = b
若T是內置資料型別,這個賦值陳述句會符合我們的期望,
但T若要是一個陣列/字串/結構體等等非內置型別,那么結果極大可能不符合我們的期望,
又如:
if(a>b)
若T是陣列,a>b將比較陣列a與b的地址高低,這很可能不是我們所希望的,
總之,模板函式很可能無法處理某些型別,
我們需要牢記,事物都有兩面性!沒有絕對好的東西,也沒有絕對壞的東西,
類模板
類模板格式
template<class T1,class T2,……,class Tn>
class 類模板名
{
//類內成員定義
}
【Note】 類模板中的類內成員在類外定義時,需要加模板引數串列
類模板的實體化
與函式模板實體化不同,類模板實體化需要在類模板名字之后加<>,然后將實體化的型別放入<>,也就是必須顯式實體化,
同樣說明適用于類模板:類模板不是類!類模板的實體化結果才是類!
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/271406.html
標籤:其他
上一篇:資料結構:圖
下一篇:【演算法】CAS的實作和無鎖編程
