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

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

作者: 从不中二的忧伤 | 来源:发表于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