C++模板
模板是一种对类型进行参数化的工具;
通常有两种形式:函数模板和类模板;
函数模板针对仅参数类型不同的函数;
例如:Max函数 :求两个数的最大值,我们需要对各种数据类型进行重载,如下
int Max(int a,int b) { return (a>b?a:b); }
double Max(double a,double b) { return (a>b?a:b); }
但如果在主函数中,我们分别定义了 char a,b; 那么在执行max(a,b);时 程序就会出错,因为我们没有定义char类型的重载版本。
此时可以采用函数模板:
template <class T> T Max(T a,T b) { return (a>b?a:b); }
函数运行结果:
int _tmain(int argc, _TCHAR* argv[]) { cout<<Max('a','b'); getchar(); return 0; }
类模板针对仅数据成员和成员函数类型不同的类。
模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。
下面进入正题:
模板使用
函数模板使用
模板定义以关键字templeate开始,后接模板形参表,模板形参表是用尖括号括住的一个或多个模板形参的列表,形参之间以逗号分隔
例如 :(在这里 typename和class没有什么区别)
template <typename T> int compare(const T& v1,const T& v2) { if(v1<v2) return -1; if(v2<v1) return 1; return 0; }
针对inline函数也存在inline函数模板
template <typename T> inline T min(const T&,const T&);
以下代码错误:
inline template<typename T> T min(const T&,const T&);
inline关键字必须在template之后
即:说明符放在模板形参列表之后,返回类型之前,不能放在关键字template之前
模板实参省略问题:
以下四种情况模板实参不能省略
- 从模板函数实参表获得的信息有矛盾
例如:
template <typename T> T add(const T& a,const T& b) { return (a+b); }
调用如下:
int _tmain(int argc, _TCHAR* argv[]) { cout<<add<int>(1,2.1)<<endl; getchar(); return 0; }
add两个参数:一个是1(int),一个是2.1(double),两个参数类型不一致,调用时必须指定一个类型,否则编译器报错
运行结果:
2. 虚拟类型参数没有出现在模板函数的形参表中
例如:
template <typename T1,typename T2,typename T3> T2 minus(const T1& a,const T3& b) { return (a-b); }
调用如下:
int _tmain(int argc, _TCHAR* argv[]) { cout<<minus<int,double,long>(2,3)<<endl; getchar(); return 0; }
T1,T3出现在形参列表,而T2没有出现在形参之中。所以必须指定T2的类型,以上调用如果写成“minus<int,int>(2,3)”,编译器也不会报错,只要指定了T2,编译器就不会报错
运行结果:
3. 需要获得特定类型的返回值,而不管参数的类型如何
例如:add<int>(a,b);
4. 函数模板含有常规形参,且常规参数的信息无法从模板函数的实参表中获得
例如:
template<class T,int nums> void sum(T data[],T& result) { result = 0; for(int i=0;i<nums;i++) { result += data[i]; } }
调用如下:
int _tmain(int argc, _TCHAR* argv[]) { int d[3] = {1,2,3}; int res; sum<int,3>(d,res); cout<<res<<endl; getchar(); return 0; }
函数模板 sum 中,nums是常规参数,nums信息无法从实参列表中获取,所以必须制定常规参数的值
运行结果:
类模板使用
类模板和函数模板都是以template开始后接模板形参列表组成,模板形参不能为空,
一但声明了类模板就可以用类模板的形参名声明类中的成员变量和成员函数,
即可以在类中使用内置类型的地方都 可以使用模板形参名来声明。比如
template<class T> class A{public: T a; T b; T hy(T c, T &d);};
类模板对象的创建:比如一个模板类A,则使用类模板创建对象的方法为A<int> m;在类A后面跟上一个<>尖括号并在里面填上相应的类型,这样的话类A中凡是用到模板形参的地方都会被int 所代替。
当类模板有两个模板形参时创建对象的方法为A<int, double> m;类型之间用逗号隔开。
对于类模板,模板形参的类型必须在类名后的尖括号中明确指定:比如A<2> m;用这种方法把模板形参设置为int是错误的(编译错误:error C2079: 'a' uses undefined class 'A<int>'),
类模板形参不存在实参推演的问题。也就是说不能把整型值2推演为int 型传递给模板形参。要把类模板形参调置为int 型必须这样指定A<int> m。
在类模板外部定义成员函数的方法为:
template<模板形参列表> 函数返回类型 类名<模板形参名>::函数名(参数列表){函数体},
比如有两个模板形参T1,T2的类A中含有一个void h()函数,则定义该函数的语法为:
template<class T1,class T2> void A<T1,T2>::h(){}。
注意:当在类外面定义类的成员时template后面的模板形参应与要定义的类的模板形参一致。
注意:模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。