美文网首页
模板与泛型 —— 模板的特化

模板与泛型 —— 模板的特化

作者: 从不中二的忧伤 | 来源:发表于2020-06-08 00:29 被阅读0次
    一、类模板特化
    二、函数模板特化

    特化: 模板是泛化的表现,可以指定不同类型做相同的表现。而特化是指对于某些特殊的类型(类型模板参数),进行特殊的处理。需要注意的是,必须先有了泛化版本,才会有对应的特化版本。


    一、类模板特化
    1、类模板全特化

    a) 常规类模板全特化

    • 全特化版本,即所有【类型模板参数】都被指定
    • 全特化版本可以有多个【类型模板参数】不同的版本
    • 编译器会优先选择满足条件的特化版本
    #include <iostream>
    using namespace std;
    
    // 泛化版本 
    template<typename T, typename U>
    class Test{
    public:
        Test()
        {
            cout << "Test<T, U>()" << endl; 
        }   
    };
    
    // 全特化版本,即所有类型模板参数都被指定 
    template<>
    class Test<int, int>{
    public:
        Test()
        {
            cout << "Test<int, int>()" << endl;
        }
    }; 
    
    // 全特化版本可以有多个【类型模板参数】不同的版本 
    template<>
    class Test<double, double>{
    public:
        Test()
        {
            cout << "Test<double, double>()" << endl;
        }
    };
    
    int main()
    {
        // 编译器会优先选择满足条件的特化版本 
        Test<char, char> t1;
        Test<int, int> t2;
        Test<double, double> t3;
        return 0;   
    } 
    
    • 全特化类模板的成员函数,必须放在类内定义,不然会报错(关于这一点,我也觉得很蛋疼,但是暂时没有找到很好的支持这一现象的原因说明)`(>﹏<)′

    正确写法:

    template<>
    class Test<int, int>{
    public:
        Test()
        {
            cout << "Test<int, int>::Test()" << endl;
        }
        // 特化版本成员函数需要在类内实现 
        void Func()
        {
            cout << "Test<int, int>::Func()" << endl;
        }
    };
    

    错误写法:

    template<>
    class Test<int, int>{
    public:
        Test()
        {
            cout << "Test<int, int>::Test()" << endl;
        }
        void Func();
    };
    
    template<>
    void Test<int, int>::Func()
    {
        cout << "Test<int, int>::Func()" << endl;
    }
    

    报错信息:
    [Error] template-id 'Func<>' for 'void Test<int, int>::Func()' does not match any template declaration



    b) 特化成员函数

    • 只对类模板中的【某些成员函数】进行特化
    • 特化的成员函数,其被构造的对象依然是【泛化版本】的,但是会调用到【特化的成员函数】。
    #include <iostream>
    using namespace std;
    
    // 泛化版本 
    template<typename T, typename U>
    class Test{
    public:
        Test()
        {
            cout << "Test<T, U>()" << endl; 
        }
        
        void Func();
    };
    
    // 泛化版本成员函数
    template<typename T, typename U>
    void Test<T, U>::Func()
    {
        cout << "Test<T, U>::Func()" << endl;   
    } 
    
    // 特化成员函数 
    template<>
    void Test<int, int>::Func()
    {
        cout << "Test<int, int>::Func()" << endl;
    }
     
    
    int main()
    {
        Test<char, char> t1;
        t1.Func();
        
        Test<int, int> t2;
        t2.Func();
    
        return 0;   
    } 
    
    2、类模板偏特化

    a) 模板参数数量 —— 偏特化

    • 偏特化的特化参数类型可以跳着来,不一定需要从最右边开始(但是从代码风格来说,不建议这样做)
    • 偏特化类模板,可以在类外进行成员函数的定义。(所以当一定需要将特化的类模板的成员函数【声明】和【定义】分开时,可以加一个无用的模板参数类型,凑成偏特化。但是我觉得这样做依然很蛋疼(っ °Д °;)っ)
    // 模板参数数量 —— 偏特化 
    template<typename U>
    class Test<int, U, int>{
    public:
        Test()
        {
            cout << "Test<int, U, int>::Test()" << endl;
        }
        
        void Func();
    };
    
    template<typename U>
    void Test<int, U, int>::Func()
    {
        cout << "Test<int, U, int>::Func()" << endl;
    }
    

    b) 模板参数范围 —— 偏特化

    • 范围的概念是说,从任意类型T,缩小为某种更小的范围T。
      比如:从 int 变成 const int
      从 T 变成 T*,或者变成T&(左值引用),或者变成T&&(右值引用)都是范围缩小。
    • 编译器在选择特化版本时,会根据<>内的类型寻找最合适的版本
      如下的 const T* 实际上是指向 const T 类型的指针,特化时会使用 <T* > 版本
      而 T* const 实际上只读的指针,不可修改指向,更符合<const T>特化版本
    // 模板参数范围 —— 偏特化
    
    template<typename T>
    class Test{
    public:
        Test()
        {
            cout << "Test<T>::Test()" << endl;
        }
        
        void Func();
    }; 
    
    template<typename T>
    void Test<T>::Func()
    {
        cout << "Test<T>::Func()" << endl;
    }
    
    // const 特化版本 
    template<typename T>
    class Test<const T>{
    public:
        Test()
        {
            cout << "Test<const T>::Test()" << endl;
        }
        void Func();
    };
    
    template<typename T>
    void Test<const T>::Func()
    {
        cout << "Test<const T>::Func()" << endl;
    }
    
    // 指针* 特化版本 
    template<typename T>
    class Test<T*>{
    public:
        Test()
        {
            cout << "Test<T*>::Test()" << endl;
        }
        void Func();
    };
    
    template<typename T>
    void Test<T*>::Func()
    {
        cout << "Test<T*>::Func()" << endl;
    }
    
    int main()
    {
        Test<char> t1;
        t1.Func();
        
        Test<const char> t2;
        t2.Func();
        
        Test<char*> t3;
        t3.Func(); 
    
        Test<const char*> t4;   // <T*> 特化版本 
        t4.Func();
        
        Test<char* const> t5;   // <const T> 特化版本 
        t5.Func(); 
    
        return 0;   
    } 
    

    二、函数模板特化

    a) 函数模板全特化

    • 全特化函数模板,实际上等价于实例化一个函数模板,并不能看作函数重载。
    • 即存在重载函数,又存在特化函数模板时,编译器会优先顺序为:
      普通函数(重载函数)> 特化版本函数模板 > 泛化版本函数模板
    // 函数模板泛化版本
    template<typename T, typename U>
    void Func(T val1, U val2)
    {
        cout << "Func<T, U>" << endl;
    }
    
    // 函数模板全特化版本
    template<>
    void Func<double, double>(double val1, double val2)
    {
        cout << "Func<double, double>" << endl;
    } 
    
    
    int main()
    {
        Func('a', 'b');
        Func(1.0, 2.0);
        
        return 0;
    }
    



    b) 函数模板偏特化

    • 实际上,函数模板是不允许被偏特化的(也是没有找到具体不允许偏特化函数模板的原因……○| ̄|_ =3)
      错误写法:
    // 函数模板偏特化版本(不被允许) 
    template<typename T>
    void Func<T, double>(T val1, double val2)
    {
        cout << "Func<T, double>" << endl;
    } 
    

    报错信息:
    [Error] function template partial specialization 'Func<T, double>' is not allowed


    模板定义、实现,建议都放在一个 .h 文件中。
    同样,模板的泛化版本和特化版本建议放在一个 .h 文件中。
    并且,应该让泛化版本放置于特化版本之前。

    相关文章

      网友评论

          本文标题:模板与泛型 —— 模板的特化

          本文链接:https://www.haomeiwen.com/subject/edbhtktx.html