模板參數
模板參數分爲類型參數和非類型參數。類型參數代表的是一個基本類型或用戶自定義的類型,而非類型參數代表一個常量。
每個參數前面都必須有關鍵字typename或者class,形式爲<typename typeparameter>或<class typeparameter>。
一個模板的非類型參數爲文字常量的例子:
#include <iostream> using namespace std; //T 是類型參數, Size是非類型參數 template <typename T, int Size> class Average { T elements[Size]; T average_value; public: Average(T *in) { average_value = (T)0; for(int i = 0; i < Size; i++) { elements[i] = in[i]; average_value += in[i]; } average_value /= Size; } void show() { cout<<"The elements are: "; for(int i = 0; i < Size; i++) { cout<<elements[i]<<" "; } cout<<endl<<"The average is: "<<average_value<<endl; } }; int main() { int arr_int[3] = {1, 2, 3}; double arr_dou[4] = {1.4, 9.8, 3.4, 0.9}; Average<int, 3> ia(arr_int); Average<double, 4> da(arr_dou); ia.show(); da.show(); return 0; }
上面的例子中,非類型參數是一個實例化的文字常量,但是,是不是模板的非類型參數只能是實例化的文字常量呢???答案
是:它也可以被實例化爲在編譯階段能夠靜態計算的表達式。看下面的例子:
一個模板的類型參數爲全局變量的例子:
#include <iostream> using namespace std; template <typename T, T *Total, T *Number> class Single { T single_value; public: Single(T s) { single_value = s; (*Total) += s; (*Number)++; } }; //定義幾個全局變量, 並不是實例化的文字常量 int Int_Total; int Int_Number; double Dou_Total; double Dou_Number; int main() { //將全局變量 Int_Total, Int_Number的地址傳給模板參數 Single<int, &Int_Total, &Int_Number> arr_int[3] = {1, 2, 3}; //將全局變量 Dou_Total, Dou_Number的地址傳給模板參數 Single<double, &Dou_Total, &Dou_Number> arr_dou[4] = {1.4, 2.3, 3.9, 4.0}; cout<<"The number of integers is: "<<Int_Number<<endl; cout<<"The total value of integers is: "<<Int_Total<<endl; cout<<"The number of doubles is: "<<Dou_Number<<endl; cout<<"The total value of doubles is: "<<Dou_Total<<endl; return 0; }
實際應用中,我們常用基本數據類型或者自定義類型來實例化模板的類型參數。那麼,是不是可以用一個模板類來實例化某個模板的類型參數呢? 當然是可以的。比如像這樣的:Array<Array<int, 3>, 4> 看下面一段程序:
#include <iostream> using namespace std; //定義一個模板類 template <typename T, int Length> class Array { public: int size; T elements[Length]; public: int GetSize() { return size; } Array():size(Length){} //size = Length //重載操作符 [] T& operator[](int i) { return elements[i]; } //友元函數, 重載了 操作符<< template <typename T> friend ostream operator<<(ostream & out, const Array<T, Length> &); }; //友元函數 //template <typename T> //這樣的寫法是錯誤的 template <typename T, int Length> //不能少,必須和類模板一致 ostream& operator<<(ostream& out, const Array<T, Length> &a) { for(int i = 0; i < a.size; i++) { out<<a.elements[i]; //判斷模板參數的類型是否爲int或者double if(typeid(a.elements[i]) == typeid(int) || typeid(a.elements[i]) == typeid(double)) out<<", "; } out<<"\b\b "; return out; } int main() { Array<double, 3> a; a[0] = 1.1; //因爲重載了操作符[],所以這句相當於 elements[0] = 1.1 a[1] = 2.2; a[2] = 3.3; cout<<a<<endl; //重載了操作符<< //將Array<int, 3>作爲一個模板參數 Array<Array<int, 3>, 4> a2; //a2爲一個二維數組,a2[4][3] int k = 0; for(int i = 0; i < a2.GetSize(); i++) for(int j = 0; j < a2[i].GetSize(); j++) //a2[i].GetSize() = 3 a2[i][j] = ++k; cout<<a2<<endl; return 0; }
使用友元函數的時候,如果友元本身是一個函數模板,則應在friend前面加template關鍵字,防止編譯器將operator<<()當做一個普通的函數看待。
>>關於模板類,還有一個更重要的應用,那就是模板的某個類型參數,其本身是另一個類模板,將它顯式地寫在模板參數列表
中。 例如定義一個模板 template <class T, int a, template<class T, int a>class A> ,參數列表中的template<class T, int
a>class A本身就是一個類模板。具體看下面的例子:
#include <iostream> using namespace std; //定義一個模板類 Array template <class T, int a> class Array { int size; public: T val[a]; Array():size(a){} //重載了 [] T & operator[](int i) { return val[i]; } void show() { cout<<"The elements of the array is: "; for(int i = 0; i < size; i++) cout<<val[i]<<" "; cout<<endl; } }; //定義一個模板類 Student template<class T, int a> class Student { int age; public: double score; Student():age(a){} void show() { cout<<"The student's age is:"<<age<<" and its score is:"<<score<<endl; } }; //定義模板類Container, 可以將另一個模板類作爲參數 template <class T, int a, template<class T, int a>class A> class Container { public: A<T, a> entity; void show() { entity.show(); } }; int main() { //將模板類 Array 作爲一個參數 Container<double, 3, Array> obj; obj.entity[0] = 1.6; obj.entity[1] = 3.4; obj.entity[2] = 2.0; obj.show(); //將模板類 Student 作爲一個參數 Container<double, 18, Student> stu; stu.entity.score = 99; stu.show(); return 0; }
一般的類模板在實例化的時候,它的類型參數和非類型參數將被替換,而類名本身不發生變化。而模板的模板參數在實例化的
時候,不但其類型參數和非類型參數要被替換,類型也必須被替換。例如,在上面的程序中,A<T, a>就被實例化爲
Array<double, 3>和Student<int, 18>。如果在一個類模板的內部要用到另一個類模板,但在實例化的時候,另一個類模板的名
字是不變的,那麼就沒有必要使用模板的模板參數,只需要在類模板的內部直接使用另一個類模板就可以了。