//模板不是函数,不能单独编译,所以要将模板信息放在同一个头文件中template<class T>class Stack{private: enum{MAX=10}; T items[MAX]; int top;public: Stack(); bool isempty(); Stack(const Stack& st); Stack& operator=(const Stack& st);};template<class T>Stack<T>::Stack(){top=0;}template<class T>bool Stack<T>::isempty(){return top==0;}template<class T>Stack<T>::Stack(const Stack& st){} //参数中也可以使用Stack<T>template<class T>Stack<T>& Stack<T>::operator=(const Stack<T> & st){} //参数中也可以使用Stack//原型中返回类型是引用,但是在定义是需要定义为Stack<T>//原型是缩写形式,只能应用在类中//即指定返回类型或者使用作用域解析符时,必须使用Stack<T>
使用模板类
Stack<int> a;Stack<string> b;//类模板必须显式提供所需的类型
非类型参数
template<class T,int n> //n为非类型参数或者表达式参数class ArrayTp{private: T ar[n]; //未使用new,使用的是栈public: ArrayTp() {}; explicit ArrayTp(const T& v); T& operator[](int i);};template<class T, int n>ArrayTp<T, n>::ArrayTp(const T& V){ for (int i = 0; i < n; i++) { ar[i] = n; }}template<class T, int n>T& ArrayTp<T, n>::operator[](int i){ return ar[i];}
非类型参数可以是整形、枚举、引用或者指针。
template<class T,double n>
是不合法的,可以是template<class T,double *n>
模板代码不能修改非类型参数的值,也不能使用参数的地址。所以不能使用n++或者&n之类的,
实例化模板时,非类型参数的值必须是常量表达式
每种数组大小都会生成自己的模板
//这会生成两个独立的类声明ArrayTp<double,10> v1;ArrayTp<double,20> v2;
使用非类型参数的优缺点:
**优点:**可以直接使用数组声明即内存栈来维护数组,执行速度偏快
**缺点:**构造函数法(不使用非类型参数)更通用,因为数组大小是存储在定义中,而不是硬编码,这样可以将不同尺寸的数组进行相互赋值,且也可以动态改变数组的大小
模板多功能性
可以将常规类的技术用于模板类,如模板类可作为基类、作为类型参数等。
template<class T>class Array{private: T entry;};template<class T>class GrowArray::public Array<Type>{};template<class T>class Stack{ Array<T> ar;};Array<Stack<int>> a;//c++11之前,最后两个符号必须隔开
递归使用模板
ArrayTp< ArrayTp<int,5>,10> twoTp
≈int twoTp[10][5]
使用多个类型参数
template<class T1,class T2>class Pair{private: T1 a; T2 b; ...};
默认类型模板参数
template<class T1,class T2=int>class Topp{};
*注意:*可以为类模板类型参数提供默认值,不能为函数模板参数提供默认值。但是函数模板和类模板都可以为非类型参数提供默认值
模板的具体化
隐式实例化
//编译器在需要对象之前不会生成类的隐式实例化ArrayTp<double,20> * pt;//声明一个pointer,目前还不需要对象pt = newArray<double ,20>;//隐式实例化
显示实例化
//使用template来声明显示实例化template class ArrayTp<string,100>;//将ArrayTp<string,100>生命为一个类//该声明必须位于模板定义所在的名称空间中
显示具体化
template<> class ArrayTp<cosnt char*>{...};ArrayTp<> a;//使用泛型模板ArrayTp<const char*> b;//使用具体化模板
部分具体化
template<class T1> class Pair<T1,int>{};//template后面的<>中是未被具体化的类型参数 如果该<>中为空,则是3.显示具体化//如果有多个模板可供选择,编译器使用具体化程度最高的模板Pair<double,double> p1;//使用Pair<T1,T2>Pair<double,int> p2;//使用Pair<T1,int>Pair<int,int> p3;//使用Pair<T1,int>
为指针提供特殊版本来实现部分具体化
template<class T>class Feeb{...}template<class T*>class Feeb{...}Feeb<char> fb1;//使用通用模板 T为charFeeb<char *> fb2;//使用T*,T为char
部门具体化可实现各种限制
//通用模板template<class T1,class T2,class T3> class Trio{};//T2与T3相同template<class T1,class T2> class Trio<T1,T2,T2>{};//T2、T3是T1的指针类型template<class T1> class Trio<T1,T1*,T1*>{};Trio<int,short,char*> t1;//通用模板Trio<int,short> t2;//Trio<T1,T2,T2>Trio<char,char*,char*> t3;//Trio<T1>
成员模板
template<class T>class A{private: template<class V> class B{}; //嵌入类 B<T> q;public: A(T t, int i) {}; template<class U> U fun(U u, T t) {return u;}};A<double> a(3.5, 3); a.fun(10, 2.3);//自动推断,U为int
//有些编译器是不能在模板中声明B类和fun方法,在外面定义,而有些可以,如果可以需要这样定义:template<class T>class A{private: template<class V> class B; B<T> q;public: A(T t, int i) {}; template<class U> U fun(U u, T t);};template<class T> template<class V> class A<T>::B {};template<class T> template<class U> U A<T>::fun(U u, T t) { return u; }//由于T、V、U是嵌套关系,所以需要这样定义:template<class T> template<class V>//而不能这样:template<class T,class V> //另外还需要使用作用域限定符来指出B与fun是A的成员
模板作为参数
template <template <typename T> class T2>
模板参数是template class T2,其中template class是类型,T2是参数。
#定义方式有点类似于非类型参数 template<class T,int n>
//可以混合使用模板参数和常规参数template<template <typename T> class T2,typename U,typename V>class Carb{};