一、模板函數重載:
函數重載是一個非常通用亦非常容易理解的編程基礎概念,既函數名相同而函數簽名不同的一組函數,在實際的調用中,編譯器會根據函數參數的不同自動選擇最為合適且最為特化的函數。在推演的過程中,如果出現多個函數均符合該調用規則,編譯器將根據其內建的特化規則,選擇最為特殊的函數作為候選函數。然而如果仍有多個候選函數的話,編譯器將報出二義性錯誤。和普通函數一樣,在C++中模板函數也同樣支援函數重載的功能,甚至可以將模板函數與普通函數混合在一起,以達到更為靈活的函數重載的效果。
在這裡,我們對於函數重載的概念本身將不再做過多的贅述了,而是將重點放在模板函數重載的應用情境和應用技巧上。下面我將給出一個利用模板函數重載計算雜湊值的程式碼範例:
1 #include <stdio.h> 2 3 template<typename T> 4 int hash_code(T v) { 5 return v.hashCode() * 2; 6 } 7 8 template<typename T> 9 int hash_code(T* v) {10 return v->hashCode();11 }12 13 int hash_code(const int v) {14 return v + 100;15 }16 17 class HashClass {18 public:19 HashClass(int v) : _v(v) {}20 int hashCode() {21 return _v + 200;22 }23 24 private:25 int _v;26 };27 28 int main() {29 HashClass c1(10); //調用的是template<typename T> int hash_code(T v)30 printf("The hash value is %d\n",hash_code(c1));31 HashClass c2(20); //調用的是template<typename T> int hash_code(T* v)32 printf("The hash value is %d\n",hash_code(&c2));33 int i3 = 30; //調用的是int hash_code(const int v)34 printf("The hash value is %d\n",hash_code(i3));35 return 0;36 }37 38 //The hash value is 42039 //The hash value is 22040 //The hash value is 130
在上面的範例程式碼中,hash_code函數可以讓編譯器根據參數的不同選擇最為合適的候選函數。在這裡模板函數和普通函數一同參與了函數重載。對於模板函數重載,主要應用於演算法領域,既對於大多數的類型可以通過泛型演算法以達到預期的效果,而對於特殊類型,則可以通過函數重載的方式,針對該類型實現另外一套更為高效的演算法。
二、模板類特化:
對於模板類而言,也同樣存在和模板函數重載類似的應用情境,但是在模板類中則是以模板類特化的方式存在。在下面的範例程式碼為生產者-消費者的任務緩衝隊列,當清空隊列中的已有元素時,亦需考慮如何釋放元素對象本身可能佔用的系統資源。這裡會根據不同的元素類型,給出不同的元素釋放類。
1 #include <stdio.h> 2 #include <vector> 3 4 using namespace std; 5 6 class Runnable { 7 public: 8 virtual void release() { 9 delete this;10 }11 };12 13 class Closable {14 public:15 virtual void close() {16 _db.close();17 delete this;18 }19 private:20 db_env _db;21 };22 23 template<typename T>24 class List { //125 public:26 void clear() { 27 _taskList.clear();28 }29 private:30 vector<T> _taskList;31 };32 33 template<typename T>34 class List<T*> { //235 public:36 void clear() {37 for (int i = 0; i < _taskList.size(); ++i)38 delete _taskList[i];39 _taskList.clear();40 }41 private:42 vector<T*> _taskList;43 };44 45 template<>46 class List<char*> { //347 public:48 void clear() {49 for (int i = 0; i < _taskList.size(); ++i)50 delete [] _taskList[i];51 _taskList.clear();52 }53 private:54 vector<char*> _taskList;55 };56 57 template<>58 class List<Runnable*> { //459 public:60 void clear() {61 for (int i = 0; i < _taskList.size(); ++i)62 _taskList[i]->release();63 _taskList.clear();64 }65 private:66 vector<Runnable*> _taskList;67 };68 69 template<>70 class List<Closable*> { //571 public:72 void clear() {73 for (int i = 0; i < _taskList.size(); ++i)74 _taskList[i]->close();75 _taskList.clear();76 }77 private:78 vector<Runnable*> _taskList;79 };80 81 int main() {82 List<Runnable*> listRunnable; //調用No 483 List<Closable*> listClosable; //調用No 584 List<int> listInt; //調用No 185 List<int*> listIntPointer //調用No 286 List<char*> listCharPointer; //調用No 387 return 0;88 }
在上面的程式碼範例中,編譯器會根據模板參數的不同而選擇不同的模板類,然而這一切對於調用者而言又是完全透明的,如果今後再增加新的特殊類型時,僅需為該類型實現一個新的特化類即可。需要說明的,該程式碼片段完全是為了示範這個C++模板特徵而編寫的,僅供參考。