標籤:dfa 版本 重載函數 固定 ios show type 有一個 類模板的部分特化
函數模板特化
函數模板特化:
- 關鍵字template後面接一對<>
- 再接模板名和一對<>,角括弧中定義這個特華的模板參數
- 函數形參表
- 函數體
template <typename T>int com(const T &v1,const T &v2) { return v1>v2?1:0;}template <>int com<const string>(const string &v1,const string &v2){ return strcmp(v1.c_str(),v2.c_str());}
特化的聲明必須與對應的模板相匹配,當調用cmp函數時,傳給他兩個const string類型的參數,編譯器調用特化版本,特化函數參數固定為const string類型,當調用其他類型(包括string)時,調用泛化版本
1.聲明特化模板
函數特化模板可以聲明而無需定義
template <>int com<const string>(const string &v1,const string &v2)
注意:
- 模板特化總是包含模板空參說明符(template<>)
- 必須包含函數形參列表,如果可以從函數形參推斷模板實參,不必顯示定義模板實參
template <>int com(const string &v1,const string &v2){ return strcmp(v1.c_str(),v2.c_str());}2.函數重載與模板特化
如果省略template<>,則是函數的重載非模板版本
template <typename T>int com(const T &v1,const T &v2) { return v1>v2?1:0;}//template <>int com(const string &v1,const string &v2){ return strcmp(v1.c_str(),v2.c_str());}
注意:
當定義非模板函數的時候,對實參應用常規轉換;特化模板的時候,對應的實參類型不應用轉換。
模板特化版本的調用中,實參類型必須與特化版本的函數型別參數完全符合,若果不完全符合,編譯器將為實參從模板定義執行個體化一個執行個體。
3.不能總是檢測到重複定義
應在一個標頭檔中包含模板特化的聲明,每個源檔案包含該標頭檔
完整代碼
#include <iostream>#include <cstring>using namespace std;template <typename T>int com(const T &v1,const T &v2) { return v1>v2?1:0;}template <>int com(const string &v1,const string &v2){ return strcmp(v1.c_str(),v2.c_str());}int main(){ int a=1,b=2; string s1="123",s2="1"; cout<<com(s1,s2)<<endl; return 0;}類模板特化
特化可以定義與模板本身不同的成員。如果一個特化無法從模板定義某個成員,該特化類型就不能使用該成員。類模板的定義不會用於顯示建立特化成員的定義。
1.類特化定義
在類特化外部定義成員時,成員前不加template<>
/* *類特化為 const char*類型,上面的函數特化類似 *此例子只是為了說明類特化模板定義成員 */void queue<const char*>::push(const char *val) { return real_queue.push(val);}2.特化成員而不特化類
template<> void queue<const char*>::push(const char *val);
與任何特化函數模板一樣,以空參的形參表開頭,在定義類的標頭檔中
3.類模板的部分特化
template <class T1,class T2>class some_templae{ //}//特化T2為int類型,T1為任何類型 template<T1>class some_template<T1,int>{ //}
注意:
- 部分特化像類模板的定義
- 部分特化的模板形參是類模板定義的形參表子集
- 部分特化形參表只列出未知模板形參的那些實參
#include <iostream>#include <cstring>using namespace std;template <class T1,class T2>class Ship{ public: Ship(T1 a1,T2 a2):a(a1),b(a2){} void show() { cout<<a<<" "<<b<<endl; } private: T1 a; T2 b;};//特化T2為int類型,T1為任何類型 template<class T1>class Ship<int,T1>//<T1,int>都可以,int和T1的位置可以交換 { public: Ship(T1 a1,int a2):a(a1),b(a2){} void show() { cout<<a<<" "<<b<<endl; } private: T1 a; int b;};int main(){ Ship<double,int> s(1.222,2);//調用通用版本,也可調用通用版本以為當生命部分特化時,編譯器會選擇最特化的版本,當無部分特化時,選擇通用版本 Ship<double,double> s2(6.66,9.99) ;//調用特化版本 s.show(); s2.show(); return 0;}
注意:
部分特化的定義與通用模板的定義不衝突,部分特化可以具有與通用模板完全不同的成員集合,類模板成員的通用定義永遠不會用執行個體化模板部分的特化成員
重載與函數模板
(1)為該函數建立候選集合:
a.與背調函數名相同的任意普通函數
b.任意模板執行個體化,模板實參發現了與調用中所用函數參數相匹配的模板實參
(2)確定哪些普通函數的的行為是可行的,候選集合中的每個執行個體模板都可行
(3)如果需要轉換來進行調用,根據轉換的種類排列可行函數,模板函數執行個體轉換有限
a.如果只有一個函數可選,就調用他
b.有多個可選,具有二義性,去掉所有模板執行個體
(4)重新排列去掉函數模板執行個體的可用函數
a.有一個則調用
b.否則具有二義性
- 如果只包含一個函數可選,就調用這個函數
- 否則具有二義性
//函數模板 template<typename Tint com(const T&,const T&);//普通函數 int com(const char*,const char*);char s1[]="sdfa",s2[]="dfaskf";com(s1,s2);//會調用普通函數,因為函數會將數組轉化為指標,調用普通函數優先於調用模板
轉換與重載函數模板
當普通函數與模板函數都同樣匹配,且一樣好時,非模板版本有限
函數模,類模板