參考:C++ 模板詳解(一)
模板:對類型進行參數化的工具;通常有兩種形式:
目的:讓程序員編寫與類型無關的代碼。
注意:模板的聲明或定義只能在全局、命名空間、類范圍內進行。即不能在局部范圍、函數內進行,比如不能在main函數中聲明或定義一個模板。
template <class 類型名1,class 類型名2,......> 返回類型 函數名(參數列表) { 函數體 }
例1:swap函數的模板:
template <class T> void swap(T& a, T& b) //參數列表使用模板形參 {
T tmp = a; //函數體內使用模板形參
a = b;
b = tmp; }
例2:max函數的模板
1 #include<iostream> 2 3 template<typename T> 4 const T& myMax(const T &a, const T &b) 5 { 6 return a > b ? a : b; 7 } 8 9 int main() 10 { 11 cout << myMax(2.1, 2.2) << endl; //輸出2.2 模板實參被隱式推演成double 12 cout << myMax<double>(2.1, 2.2) << endl; //輸出2.2 顯示指定模板參數。 13 cout << myMax<int>(2.1, 2.2) << endl; //輸出2 顯示指定的模板參數,會將參數轉換為int。
14
15 return 0; 16 }
template<class 形參名1, class 形參名2, ...> class 類名 { ... };
例:一個類模板的例子:
template<class T> class A { public: T a; //類成員使用模板形參 T b; T func(T c, T &d); };
template<模板形參列表> 函數返回類型 類名<模板形參名>::函數名(參數列表) { 函數體 }
例:比如模板類A,有兩個模板形參T1,T2,有一個成員函數 void func(),則外部定義該函數的語法為:
template<class T1, class T2> //與類一致 void A<T1, T2>::func() //類名也要加上模板參數列表 { }
注意:當在類外面定義類的成員時,template後面的模板形參應與所定義的類的模板形參一致。
有三種類型的模板形參:類型形參,非類型形參和模板形參。
類型形參由關鍵字class或typename後接說明符構成,如
template<class T> void func(T a) { };
函數模板,同一個類型形參,必須用相同類型的實參來初始化,比如
template<class T> void func(T a, T b) { }
類模板,其內部成員函數,則沒有上述的限制,比如
template<class T> class A { public: T func(T a, T b); //或者T func(const T &a, const T &b); 普通引用會編譯報錯 };
例:模板類的對象調用成員函數:
1 #include <iostream> 2 using namespace std; 3 4 template<class T> 5 class A 6 { 7 public: 8 A(); 9 T func(T a, T b); 10 }; 11 12 template<class T> //類外定義構造函數 13 A<T>::A() 14 { 15 } 16 17 template<class T> //類外定義成員函數 18 T A<T>::func(T a, T b) 19 { 20 return a + b; 21 } 22 23 int main(int argc, char *argv[]) 24 { 25 A<int> ia; //模板實參為int類型的對象 26 cout << ia.func(3, 2.1) << endl; //輸出5 27 28 A<double> da; 29 cout << da.func(3, 2.1) << endl; //輸出5.1 30 31 return 0; 32 }
也就是內置類型形參,如
template<class T, int a> //int a 就是非類型形參 class B { };
非類型形參有幾點要注意的:
template <class T, int a> class A { };
如果有int b; 這時 A<int, b> m; 將出錯,因為b不是常量;如果有 const int b; 這時 A<int, b> m; 正確,因為這時b是常量。
template<class T, int a> void func(T b) { }
若用func(2)調用,會出現無法為非類型形參a推演出參數的錯誤;可以用顯示模板實參來解決,如用func<int, 3>(2); 把非類型形參a設置為整數3。顯示模板實參在後面介紹。
//1 數組到指針,函數到指針的轉換 template<int *a> class A { }; int b[10]; A<b> m; //數組轉換成指針 //2 const修飾符的轉換 template<const int *a> class A { }; int b; A<&b> m; //從int*轉換成const int * //3 提升轉換 template<int a> class A { }; const short b = 2; A<b> m; //short到int提升 //4 整數轉換 template<unsigned int a> class A { }; A<3> m; //int到unsigned int轉換 //5 常規轉換
1 #include <iostream> 2 #include <string> 3 #include <stdexcept> //std::out_of_range 4 #include <cstdlib> //EXIT_FAILURE 5 using namespace std; 6 7 /*********模板類,聲明開始,一般都是放在頭文件的*********/ 8 9 template<class T, int MAXSIZE> 10 class myStack 11 { 12 public: 13 myStack(); 14 void push(T const &); //入棧 15 void pop(); //出棧 16 T top() const; //返回棧頂 17 18 bool empty() const //判斷是否為空 19 { 20 return size == 0; 21 } 22 23 bool full() const //判斷棧是否已滿 24 { 25 return size == MAXSIZE; 26 } 27 28 private: 29 T elems[MAXSIZE]; //使用數組存放棧元素,由於非類型形參MAXSIZE在類內是一個常量,所以可以用來聲明數組大小 30 int size; //棧已使用空間 31 }; 32 33 /**********模板類,聲明結束,定義成員函數開始********/ 34 35 template<class T, int MAXSIZE> 36 myStack<T, MAXSIZE>::myStack(): size(0) //構造函數,初始化為空 37 { 38 } 39 40 template<class T, int MAXSIZE> 41 void myStack<T, MAXSIZE>::push(T const &new_elem) //入棧 42 { 43 if(size == MAXSIZE) 44 { 45 throw out_of_range("myStack::push(): stack is full"); 46 } 47 elems[size++] = new_elem; 48 } 49 50 template<class T, int MAXSIZE> 51 void myStack<T, MAXSIZE>::pop() //棧頂出棧 52 { 53 if(size <= 0) 54 { 55 throw out_of_range("myStack::pop(): stack is empty"); 56 } 57 --size; 58 } 59 60 template<class T, int MAXSIZE> 61 T myStack<T, MAXSIZE>::top() const //返回棧頂元素 62 { 63 if(size <= 0) 64 { 65 throw out_of_range("myStack::top(): stack is empty"); 66 } 67 return elems[size - 1]; 68 } 69 70 /***********成員函數定義結束**********************/ 71 72 int main(int argc, char *argv[]) 73 { 74 try 75 { 76 myStack<int, 20> int20Stack; 77 myStack<int, 40> int40Stack; 78 myStack<string, 40> stringStack; 79 80 int20Stack.push(7); 81 cout << int20Stack.top() << endl; //輸出7 82 int20Stack.pop(); 83 84 for(int i = 0; i < 40; ++i) 85 int40Stack.push(i); 86 cout << int40Stack.top() << endl; //輸出39 87 //int40Stack.push(41); //繼續添加元素,會拋出異常,輸出Exception: myStack::push(): stack is full 88 89 stringStack.push("hello"); 90 cout << stringStack.top() << endl; //輸出hello 91 stringStack.pop(); 92 //stringStack.pop(); //繼續出棧,會拋出異常,輸出Exception: myStack::push(): stack is empty 93 94 return 0; 95 } 96 catch(out_of_range const &ex) 97 { 98 cerr << "Exception: " << ex.what() << endl; 99 return EXIT_FAILURE; 100 } 101 }
T是類型參數,
T也是模板形參(有兩種模板形參:類型形參和非類型形參),
T還是模板形參表(你表項只有一項).