zoukankan      html  css  js  c++  java
  • 类模板

    ---恢复内容开始---

    感觉C++ templates这本书写的不怎么好,挑写重点记一下:

    1 与函数模板一样,只能在同一个头文件中声明和定义类。

    类模板的声明

    类模板的声明和函数模板的声明很相似:在声明之前,我们先(用一条语句)声明作为类型参数的标志符;我们继续使用T作为标志符;

    template <typename T>
    class Stack{
             ...
    };
    

      在此,我们可以使用关键字class代替typename。

      在类模板的内部,T可以像其他任何类型一样,用于声明成员变量和成员函数。

      这个类的类型是Stack<T>,其中T是模板参数,因此,当在声明中需要使用该类的类型时,你必须使用Stack<T>.但是,如果在类模板自己的作用域中,我们可以直接使用模板名而不提供实参:

      例如:

    template <typename T>
    class Stack{
        ...
        Stack(Stack<T> const &);  //拷贝构造函数
        Stack<T> &operator==(Stack<T> const &);  //赋值运算符
    };
    可以简化为
    template <typename T>
    class Stack{
        ...
        Stack(Stack const &);  //拷贝构造函数
        Stack &operator==(Stack const &);  //赋值运算符
    };
    
    (这里感觉C++ templates中写的有点问题,上面是这样说的:当使用类名而不是类的类型时,就应该只用Stack;譬如,当你指定类的名称、类的构造函数、析构函数时,就应该使用Stack。)
    
    按照C++ primer 中就不是这样的,只要在类模板的作用域中就都可以省略掉T。上机测试也没问题。。
    

      成员函数的实现

    为了定义类模板的成员函数,你必须指定该成员函数是一个函数模板,而且你还需要使用这个类模板的完整限定符。因此,类型Stack<T>的成员函数push()的实现如下:

    template<typename T>
    void Stack<T>::push(Tconst &elem)
    {
        elems.push_back(elem):
    }
    

    显然,对于类模板的任何成员函数,你都可以把它实现为内联函数,将它定义于类声明里面。例如:

    template<typename T>
    class Stack{
        ...
        void push(T const &elem){
            elems.push_back(elem);
        }
    };

    类模板的使用

    注意:只有那些被调用的成员函数,才会产生这些函数的实例化代码,对于类模板,成员函数只有在被使用的时候才会被实例化。显然,这样可以节省空间和时间;另一个好处是:对于那些“未能提供所有成员函数中所有操作的”类型,你也可以使用该类型来实例化类模板,只要对那些“未能提供某些操作的”成员函数,模板内部不使用就可以。例如,某些类模板中的成员函数会使用operator<来排序元素;如果不调用这些“使用operator<的”成员函数,那么对于没有定义operator<的类型,也可以被用来实例化该类模板。

    类模板的特化

    你可以用模板实参来特化类模板,和函数模板的重载类似,通过特化类模板,你可以优化基于某种特定类型的实现,或者克服某种特定类型在实例化类模板时所出现的不足。另外,如果要特化一个类模板,你还要特化该类模板的所有成员函数。

    为了特化一个类模板,你必须在起始处声明一个template<>,接下来声明用来特化类模板的类型。这个类型被用作模板实参,且必须在类名的后面直接指定:

    template<>
    class Stack<std::string>{
               ........      
    };
    

      进行类模板的特化时,每个成员函数都必须重新定义为普通函数,原来模板函数中的每个T也相应地被进行特化的类型取代:

    void Stack<std::string>::push(std::string const &elem)
    {
        elems.push_back(elem);
    }
    

      注意:在全特化类模板时,成员的特化前面不需要加template<>。

    局部特化


    类模板可以被局部特化。你可以在特定的环境下指定类模板的特定实现,并且要求某些模板参数仍然必须由用户来定义。例如类模板:

      

    template<typename T1,typename T2>
    class MyClass{
            .....
    };
    

      就可以有下面几种局部特化:

    //局部特化:两个模板参数具有相同的类型

    template<typename T>
    class MyClass<T,T>{
            ...
    };
    //局部特化:第2个模板参数的类型是int
    template<typename T>
    class MyClass<T,int>{
            ...
    };
    
    //局部特化:两个模板参数都是指针类型
    template<typename T1,typename T2>
    class MyClass<T1*,T2*>{
            ...
    };
    

      下面的例子展示各种声明会使用哪个模板:

    MyClass<int,float> mif;   //MyClass<T1,T2>
    MyClass<float,float> mff; //MyClass<T,T>
    MyClass<float,int> mfi;  //MyClass<T,int>
    MyClass<int*,float*> mp; //MyClass<T1*,T2*>
    

      如果同时有多个局部特化同等程度地匹配某个声明,那么就称该声明具有二义性:

    MyClass<int,int> m; //错误:同等匹配MyClass<T,T>和MyClass<T,int>
    MyClass<int*,int*> m;//错误:同等匹配MyClass<T,T>和MyClass<T1*,T2*>
    

      为了解决第2中二义型,你可以另外提供一个指向相同类型指针的特化:

    template<typename T>
    MyClass<T*,T*>{
            ...
    };
    

      缺省模板实参

    对于类模板,你还可以为模板参数定义缺省值;这些值就被称为缺省模板实参;而且,它们还可以引用之前的模板参数。例如,在Stack<>中,你可以把用于管理元素的容器定义为第2个模板实参,并且使用std::vector<>作为它的缺省值:

    template<typename T,typename CONT=std::vector<T> >(记得加空格)
    class Stack{
        ....
        public:
            void push(T const &);
    };
    
    template<typename T,typename CONT>
    void Stack<T,CONT>::push(T const& elem)
    {
        elems.push_back(elem);
    }
    

      可以看到:我们的类模板含有两个模板参数,因此每个成员函数的定义都必须具有这两个参数。

    小结:

    • 类模板是具有如下性质的类:在类的实现中,可以有一个或多个类型还没与被指定。
    • 为了使用类模板,你可以传入某个具体类型作为模板实参;然后编译器将会基于该类型来实例化类模板。
    • 对于类模板而言,只有那些被调用的成员函数才会被实例化
    • 你可以用某种特定类型特化类模板
    • 你可以用某种类型局部特化类模板
    • 你可以为类模板的参数定义缺省值,这些值还可以引用之前的模板参数。
  • 相关阅读:
    nodejs发送http请求
    Codeforces Round #655 (Div. 2)
    闇の連鎖 树上LCA + 树上差分
    Tree 换根dp
    「水」悠悠碧波 kmp
    HH的项链
    Educational Codeforces Round 90 (Rated for Div. 2)
    巡逻(论为什么第二次求直径要用dp)
    Codeforces Round #651 (Div. 2)
    Treap板子
  • 原文地址:https://www.cnblogs.com/wuchanming/p/4059905.html
Copyright © 2011-2022 走看看