函数模板:
模板的定义:
template <class/typename 类型形参名,class/typename 类型形参名,......>
返回类型
函数名(参数列表)
{ ...函数体...}
模板的使用:
不能在函数调用的参数中指定模板形参的类型,对函数模板的调用应使用实参推演来进行,即只能进行 h(2,3) 这样的调用(即:函数名(参数,参数) ),或者int a, b; h(a,b)。
template<classT1,class T2,class T3>
T1 sum(T1 a,T2 b,T3 c){
return a+b+c;
}
sum<double,short,int>(1.1,3,257)
类模板:
模板的定义:
template<class/typename 类型形参名,class/typename类型形参名,…>
class
类名
{ ...类体... };
template<class T> class A{
public:
T g(T a,T b);
A();
};
模板的使用:
类模板对象的创建:比如一个模板类A,则使用类模板创建对象的方法为A<int> m;在类A后面跟上一个<>尖括号并在里面填上相应的类型,这样的话类A中凡是用到模板形参的地方都会被int 所代替。当类模板有两个模板形参时创建对象的方法为A<int,double> m;类型之间用逗号隔开。
对于类模板,模板形参的类型必须在类名后的尖括号中明确指定。
Stack<int,40> int40Stack; // 可以存储40个int元素的栈
在类模板外部定义成员函数的方法为:
在类外面定义类的成员时template后面的模板形参应与要定义的类的模板形参一致
template<classT1,int a> void Ci<T1,a>::g(){}
template<classT1,int &a> void Cip<T1,a>::g(){}
template<模板形参列表> 函数返回类型 类名<模板形参名>::函数名(参数列表){函数体},
template <class T,int MAXSIZE>
void Stack<T,MAXSIZE>::Stack():numElems(0) { //初始时栈不含元素不做任何事情 }
template<class T> T A<T>::g(Ta,T b){
return a+b;
}
template<class T1,class T2=int> void D< T1>::g(){}
在类模板外部定义带有默认类型的形参时,在template的形参表中默认值应省略。
非类型模板形参:模板的非类型形参也就是内置类型形参,如template<class T, int a> class B{};其中int a就是非类型的模板形参。
非类型形参在模板定义的内部是常量值,也就是说非类型形参在模板的内部是常量。
非类型模板的形参只能是整型,指针和引用,像double,String, String **这样的类型是不允许的。但是double &,double *,对象的引用或指针是正确的。
当模板的形参是整型时调用该模板时的实参必须是整型的,且在编译期间是常量,比如template <class T, int a> class A{};如果有int b,这时A<int,b> m;将出错,因为b不是常量,如果const int b,这时A<int, b> m;就是正确的,因为这时b是常量。
Ci<int,3> //正确,数值R是一个int型常量,输出"classCi g() int"
const int a2=3; Ci<int,a2> mci1; //正确,因为a2在这里是const型的常量。
Cip<int,&e> mcip; //当e是全局变量时,对全局变量的引用或地址是常量表达式
非类型形参一般不应用于函数模板中,比如有函数模板template<class T, int a> void h(T b){},若使用h(2)调用会出现无法为非类型形参a推演出参数的错误,对这种模板函数可以用显示模板实参来解决,如用h<int,3>(2)这样就把非类型形参a设置为整数3。