模板與標準模板庫

模板參數

模板參數分爲類型參數非類型參數。類型參數代表的是一個基本類型或用戶自定義的類型,而非類型參數代表一個常量

每個參數前面都必須有關鍵字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>。如果在一個類模板的內部要用到另一個類模板,但在實例化的時候,另一個類模板的名

字是不變的,那麼就沒有必要使用模板的模板參數,只需要在類模板的內部直接使用另一個類模板就可以了。

 

 


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章