C++語法-函數模板
參考《C++ Primer Plus 第6版》
函數模板定義
一般將模板放在頭文件中,並在需要使用模板的文件中包含頭文件。
函數模板也可以重載,其函數特徵標必須不同。
#include <iostream> using namespace std; //定義一個模板,用於交換兩個變量的值 template<typename T> void Swap(T& x,T& y) { T tmp = x; x = y; y = tmp; cout << " - Template Swap(T&,T&)" << endl; } int main(int argc,char** argv) { int a = 3; int b = 4; cout << " - 0" << endl; cout << " a = " << a << endl; cout << " b = " << b << endl; Swap(a,b); cout << " a = " << a << endl; cout << " b = " << b << endl; return 0; }
顯示具體化
當一般的函數模板不能滿足特定需求時,可以通過顯示具體化(explicit specialization)在保證不修改函數參數的情況下滿足條件。
如上例,需要定義一個交換指定類型的具體函數,如下所示:
#include <iostream> using namespace std; //定義一個模板,用於交換兩個變量的值 template<typename T> void Swap(T& x,T& y) { T tmp = x; x = y; y = tmp; cout << " - Template Swap(T&,T&)" << endl; } struct Job { char name[40]; double salary; int floor; }; void showJob(const Job& j); template<> void Swap<Job>(Job& jx,Job& jy); //顯示具體化聲明 int main(int argc,char** argv) { Job ja = {"James Bond",1000.0,7}; Job jb = {"Indianna Smith",1500.0,8}; showJob(ja); showJob(jb); Swap(ja,jb); showJob(ja); showJob(jb); return 0; } void showJob(const Job& j) { cout << j.name << endl << " -- salary:" << j.salary << endl << " -- floor:" << j.floor << endl; } /** * 顯示具體化 * 1. 顯示具體化的原型和定義以template<>開頭; * 2. 在函數名後指定參數類型,如Swap<Job>; * 3. <Job>也可以省略,爲可選; * 4. 具體化優先於常規函數模板 * */ template<> void Swap<Job>(Job& jx,Job& jy) { cout << "template<> Swap<Job>" << endl; double tmp_salary = jx.salary; int tmp_floor = jx.floor; jx.salary = jy.salary; jx.floor = jy.floor; jy.salary = tmp_salary; jy.floor = tmp_floor; }
-
顯示具體化的原型和定義以template<>開頭;
-
在函數名後指定參數類型,如Swap<Job>;
-
<Job>也可以省略,爲可選;
-
具體化優先於常規函數模板.
實例化
函數模板本身並不是函數,也不構成給函數定義。在需要的時候,編譯器使用模板爲特定類型生成函數定義,即得到模板實例(initialization)。在使用常規函數模板時,都會進行實例化,此即隱式實例化(implicit initialization)。除此之外,還可以顯示地進行實例化,即顯示實例化(explicit initialization)。
顯示實例化的做法是在聲明前加關鍵字template,並且用<>符號指定類型:
template void Swap<double>(double&,double&);
-
與顯示具體化不同的是,顯示實例化前面的關鍵字template後面不跟<>符號,而顯示具體化必須要有<>符號。
-
顯示具體化必須要有自己的函數定義。
-
同一個文件中使用同一種類型的顯示具體化和顯示實例將會出錯。
除了聲明顯示具體化外,還可以直接通過使用函數來創建顯示實例化,如下代碼所示:
//... double a = 1.2; double b = 2.3; Swap<double>(a,b); //顯示實例化 cout << a << " , " << b << endl; //...
上面的代碼並沒有先聲明顯示實例化。
選擇函數版本
優先級排序:
非模板函數 > 具體化 > 常規模板函數
最佳到最差的順序
-
完全匹配;
-
提升轉換,如char自動轉換爲int;
-
標準轉換,如int轉換爲char;
-
用戶自定義的轉換,如類聲明中定義的轉換。
兩個函數完全匹配的情況
這種情況下,有時可以完成重載解析:
-
參數爲指向非const數據的指針和引用優先於指向const指針和引用參數,注意,參數爲指針或者引用;
-
非模板函數優先於模板函數(包括顯示具體化)。
注意:參數完全匹配的引用版和非引用版,存在二義性。
自定義選擇
在模板和函數相同的時候,也能指定調用模板,如下所示,通過在函數名後面使用<>符號即可:
#include <iostream> #include <functional> template<typename T> T lesser(T a,T b) { cout << "template<T>" << endl;; return a < b?a:b; } //默認對於int類型,選擇此函數 int lesser(int a,int b) { cout << "int lesser" << endl; return a < b?a:b; } int main(int argc,char** argv) { cout << lesser(3,4) << endl; cout << lesser<>(3,4) << endl; //選擇模板,實例化,T爲int; return 0; }