(1)要注意什么时候使用类名,什么时候使用类的类型
例如:
- #include <vector>
- #include<stdexcept>
- template<typename T>
- class Stack{
- private:
- std::vector<T> elems;
- public:
- void push(T const&);
- void pop();
- T top() const;
- bool empty() const{
- return elems.empty();
- }
- };
- template<typename T>
- void Stack<T>::push(T const& elem)
- {
- elems.push_back(elem);
- }
- template<typename T>
- void Stack<T>::pop(){
- if(elems.empty()){
- throw std::out_of_range("Stack<T>::pop(): empty elems");
- }
- elems.pop_back();
- }
- template<typename T>
- T Stack<T>::top() const{
- if(elems.empty()){
- throw std::out_of_range("Stack<T>::pop(): empty elems");
- }
- return elems.back();
- }
当实现自己的构造函数、析构函数时,应该使用类名,而在实现自己的拷贝构造函数和赋值函数时应使用类型:
如:
- template <typenaem T>
- class Stack{
- private:
- ....
- Stack(Stack<T> const&);
- Stack<T>& operator=(Stack<T> const&);
- ....
- };
拷贝构造函数中的参数是类型,所以使用了Stack<T>表示。
(2)成员函数的实现:
如
- template<typename T>
- void Stack<T>::push(T const& elem)
- {
- elems.push_back(elem);
- }
为了定义一个类模板的成员函数,必须指定该成员函数是一个模板函数,而且还要使用这个类模板的完整类型限定符。如
Stack<T>.
(3)类模板的使用
注意,只有那些被调用的成员函数,才能产生函数的实例化代码。对与类模板,成员函数只有在被使用的时候才会被实例化。这样可以节省空间和时间;另一个好处就是:对于那些“未能提供所有成员函数中所有操作的”类型,你也可以使用该类型来实例化类模板,只要对那些“未能提供某些操作的”成员函数,模板内部不使用即可。
(4)类模板的特化
通过特化类模板,我们可以优化基于某种特定类型的实现,或者克服某种特定类型在实例化类模板时所出现的不足。另外,如果要特化一个类模板,你还要特化该类模板的所有成员函数。虽然也可以只特化某个成员函数,但是这个做法并没有特化整个类,也就没有特化整个类模板。
为了特化一个类模板,你必须在起始处声明一个template<>,接下来声明用来特化类模板的类型。这个类型被用作模板实参,且必须在类名的后面直接指定:
- template<>
- class Stack<std::string>{
- .......
- }
进行类模板的特化时,每个成员函数都必须重新定义为普通函数,原来模板函数中的每个T也应被进行特化的类型取代:
- void Stack<std::string>::push(std::string const& elem)
- {
- elems.push_back(elem);
- }
(5)局部特化
类模板可以被局部特化。我们可以在特定的环境下指定类模板的特定实现,并且要求某些模板参数仍然必须由用户来定义。例如类模板:
- template<typename T1,typename T2>
- class MyClass{
- .....
- };
可以有以下几种局部特化:
- template<typename T>
- class MyClass<T,T>{
- .....
- };
- template<typename T>
- class MyClass<T,int>{//第二个模板参数的类型是int
- .....
- };
但是要注意其中有可能产生的二义性。
(6)缺省模板实参
对于类模板,你还可以为模板参数定义缺省值;这些值就被称为缺省模板参数;而且,它们还可以引用之前的模板参数。例如,在类Stack<>中,你可以把用于管理元素的容器定义为第2个模板参数,并且使用std::vector<>作为它的缺省值:
- #include<vector>
- #include<stdexcept>
- template <typename T, typename Cont=std::vector<T> >
- class Stack{
- private:
- Cont elems;
- public:
- void push(T const&);
- void pop();
- T top() const;
- bool empty() const{
- return elems.empty();
- }
- };
- template <typename T,typename Cont>
- void Stack<T ,Cont>::push(T const& elem)
- {
- elems.push_back(elem);
- }
- template<typename T,typename Cont>
- void Stack<T,Cont>::pop()
- {
- if(elems.empty()){
- throw std::out_of_range("Stack<>::pop(): empty stack");
- }
- elems.pop_back();
- };
- template<typename T,typename Cont>
- T Stack<T,Cont>::top() const{
- if(elems.empty()){
- throw std::out_of_range("Stack<>::top():empty stack");
- }
- return elems.back();
- }
- #include<iostream>
- #include<deque>
- #include <cstdlib>
- #include "stack3.h"
- int main()
- {
- try
- {
- Stack<int> intStack;
- Stack<double,std::deque<double> >dblStack;
- intStack.push(7);
- std::cout<<intStack.top()<<std::endl;
- intStack.pop();
- dblStack.push(42.42);
- std::cout<<dblStack.top()<<std::endl;
- dblStack.pop();
- dblStack.pop();
- }
- catch (std::exception const& ex)
- {
- std::cerr <<"Exception:"<<ex.what()<<std::endl;
- return EXIT_FAILURE;
- }
- }