模板与标准模板库

模板参数

模板参数分为类型参数非类型参数。类型参数代表的是一个基本类型或用户自定义的类型,而非类型参数代表一个常量

每个参数前面都必须有关键字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>。如果在一个类模板的内部要用到另一个类模板,但在实例化的时候,另一个类模板的名

字是不变的,那么就没有必要使用模板的模板参数,只需要在类模板的内部直接使用另一个类模板就可以了。

 

 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值