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



