C++模板的特化详解(函数模版特殊,类模版特化)

                       
 

代码上传至

   

https://github.com/gatieme/AderXCoding/tree/master/language/cpp/template_special

   

或者

   

https://github.com/gatieme/STLSourceAnalysis/tree/master/stl-gatieme/3-iterator 下的3templatespecial_class.cpp和3templatespecial_func.cpp

   

参照

   

小解C++模板特化

   

C++模板的特化

   

模板的全特化与偏特化

模版与特化的概念


函数模版与类模版


C++中模板分为函数模板和类模板

  • 函数模板:是一种抽象函数定义,它代表一类同构函数。

  • 类模板:是一种更高层次的抽象的类定义。

特化的概念


所谓特化,就是将泛型的东东搞得具体化一些,从字面上来解释,就是为已有的模板参数进行一些使其特殊化的指定,使得以前不受任何约束的模板参数,或受到特定的修饰(例如const或者摇身一变成为了指针之类的东东,甚至是经过别的模板类包装之后的模板类型)或完全被指定了下来。

模板特化的分类


针对特化的对象不同,分为两类:函数模板的特化类模板的特化

  • 函数模板的特化

    当函数模板需要对某些类型进行特化处理,称为函数模板的特化。

  • 类模板的特化

    当类模板内需要对某些类型进行特别处理时,使用类模板的特化。

特化整体上分为全特化偏特化
*   全特化

就是模板中模板参数全被指定为确定的类型。全特化也就是定义了一个全新的类型,全特化的类中的函数可以与模板类不一样。
   
   
  • 1
  • 2
  • 3
  • 偏特化

    就是模板中的模板参数没有被全部确定,需要编译器在编译时进行确定。

 

全特化的标志就是产生出完全确定的东西,而不是还需要在编译期间去搜寻适合的特化实现,貌似在我的这种理解下,全特化的 东西不论是类还是函数都有这样的特点,

  1. 模板函数只能全特化,没有偏特化(以后可能有)。

  2. 模板类是可以全特化和偏特化的。

 

template <>然后是完全和模板类型没有一点关系的类实现或者函数定义,如果你要说,都完全确定下来了,那还搞什么模板呀,直接定义不就完事了?

   

但是很多时候,我们既需要一个模板能应对各种情形,又需要它对于某个特定的类型(比如bool)有着特别的处理,这种情形下特化就是需要的了。

  • 全特化的标志:template <>然后是完全和模板类型没有一点关系的类实现或者函数定义
  • 偏特化的标志:template

函数模版特化


目前的标准中,模板函数只能全特化,没有偏特化

 

至于为什么函数不能偏特化,似乎不是因为语言实现不了,而是因为偏特化的功能可以通过函数的重载完成。

函数模版的特化技巧


函数模板的特化:当函数模板需要对某些类型进行特别处理,称为函数模板的特化。

例如,我们编写了一个泛化的比较程序

template <class T>int compare(const T &left, const T&right){    std::cout <<"in template<class T>..." <<std::endl;    return (left - right);}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这个函数满足我们的需求了么,显然不,它支持常见int, float等类型的数据的比较,但是不支持char*(string)类型。

所以我们必须对其进行特化,以让它支持两个字符串的比较,因此我们实现了如下的特化函数。

template < >int compare<const char*>(const char* left, const char* right){    std::cout <<"in special template< >..." <<std::endl;    return strcmp(left, right);}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

也可以

template < >int compare(const char* left, const char* right){    std::cout <<"in special template< >..." <<std::endl;    return strcmp(left, right);}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

示例程序1–比较两个数据


#include <iostream>#include <cstring>///  模版特化template <class T>int compare(const T left, const T right){    std::cout <<"in template<class T>..." <<std::endl;    return (left - right);}//  这个是一个特化的函数模版template < >int compare<const char*>(const char* left, const char* right){    std::cout <<"in special template< >..." <<std::endl;    return strcmp(left, right);}//  特化的函数模版, 两个特化的模版本质相同, 因此编译器会报错// error: redefinition of 'int compare(T, T) [with T = const char*]'|//template < >//int compare(const char* left, const char* right)//{//    std::cout <<"in special template< >..." <<std::endl;////    return strcmp(left, right);//}//  这个其实本质是函数重载int compare(char* left, char* right){    std::cout <<"in overload function..." <<std::endl;    return strcmp(left, right);}int main( ){    compare(1, 4);    const char *left = "gatieme";    const char *right = "jeancheng";    compare(left, right);    return 0;}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

函数模版的特化,当函数调用发现有特化后的匹配函数时,会优先调用特化的函数,而不再通过函数模版来进行实例化。

示例程序二-判断两个数据是否相等

#include <iostream>#include <cstring>using namespace std;//函数模板template<class T>bool IsEqual(T t1,T t2){    return t1==t2;}template<> //函数模板特化bool IsEqual(char *t1,char *t2){    return strcmp(t1,t2)==0;}int main(int argc, char* argv[]){    char str1[]="abc";    char str2[]="abc";    cout<<"函数模板和函数模板特化"<<endl;    cout<<IsEqual(1,1)<<endl;    cout<<IsEqual(str1,str2)<<endl;    return 0;}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

类模版特化


类模板的特化:与函数模板类似,当类模板内需要对某些类型进行特别处理时,使用类模板的特化。例如:

这里归纳了针对一个模板参数的类模板特化的几种类型

  • 一是特化为绝对类型;

  • 二是特化为引用,指针类型;

  • 三是特化为另外一个类模板。

这里用一个简单的例子来说明这三种情况:

特化为绝对类型


也就是说直接为某个特定类型做特化,这是我们最常见的一种特化方式, 如特化为float, double等

#include <iostream>#include <cstring>#include <cmath>// general versiontemplate<class T>class Compare{public:    static bool IsEqual(const T& lh, const T& rh)    {        std::cout <<"in the general class..." <<std::endl;        return lh == rh;    }};// specialize for floattemplate<>class Compare<float>{public:    static bool IsEqual(const float& lh, const float& rh)    {        std::cout <<"in the float special class..." <<std::endl;        return std::abs(lh - rh) < 10e-3;    }};// specialize for doubletemplate<>class Compare<double>{public:    static bool IsEqual(const double& lh, const double& rh)    {        std::cout <<"in the double special class..." <<std::endl;        return std::abs(lh - rh) < 10e-6;    }};int main(void){    Compare<int> comp1;    std::cout <<comp1.IsEqual(3, 4) <<std::endl;    std::cout <<comp1.IsEqual(3, 3) <<std::endl;    Compare<float> comp2;    std::cout <<comp2.IsEqual(3.14, 4.14) <<std::endl;    std::cout <<comp2.IsEqual(3, 3) <<std::endl;    Compare<double> comp3;    std::cout <<comp3.IsEqual(3.14159, 4.14159) <<std::endl;    std::cout <<comp3.IsEqual(3.14159, 3.14159) <<std::endl;    return 0;}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

如果期望使用偏特化,那么

template<class T1, class T2>class A{}template<class T1>class A<T1, int>{}
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

特化为引用,指针类型


template <class _Iterator>struct iterator_traits {  typedef typename _Iterator::iterator_category iterator_category;  typedef typename _Iterator::value_type        value_type;  typedef typename _Iterator::difference_type   difference_type;  typedef typename _Iterator::pointer           pointer;  typedef typename _Iterator::reference         reference;};// specialize for _Tp*template <class _Tp>struct iterator_traits<_Tp*> {  typedef random_access_iterator_tag iterator_category;  typedef _Tp                         value_type;  typedef ptrdiff_t                   difference_type;  typedef _Tp*                        pointer;  typedef _Tp&                        reference;};// specialize for const _Tp*template <class _Tp>struct iterator_traits<const _Tp*> {  typedef random_access_iterator_tag iterator_category;  typedef _Tp                         value_type;  typedef ptrdiff_t                   difference_type;  typedef const _Tp*                  pointer;  typedef const _Tp&                  reference;};
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

当然,除了T*, 我们也可以将T特化为 const T*, T&, const T&等,以下还是以T*为例:

// specialize for T*template<class T>class Compare<T*>{public:    static bool IsEqual(const T* lh, const T* rh)    {        return Compare<T>::IsEqual(*lh, *rh);    }};
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

这种特化其实是就不是一种绝对的特化, 它只是对类型做了某些限定,但仍然保留了其一定的模板性,这种特化给我们提供了极大的方便, 如这里, 我们就不需要对int*, float*, double*等等类型分别做特化了。

这其实是第二种方式的扩展,其实也是对类型做了某种限定,而不是绝对化为某个具体类型,如下:

// specialize for vector<T>template<class T>class Compare<vector<T> >{public:    static bool IsEqual(const vector<T>& lh, const vector<T>& rh)    {        if(lh.size() != rh.size()) return false;        else        {            for(int i = 0; i < lh.size(); ++i)            {                if(lh[i] != rh[i]) return false;            }        }        return true;    }};
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

这就把IsEqual的参数限定为一种vector类型, 但具体是vector还是vector, 我们可以不关心, 因为对于这两种类型,我们的处理方式是一样的,我们可以把这种方式称为“半特化”。

当然, 我们可以将其“半特化”为任何我们自定义的模板类类型:

// specialize for any template class typetemplate <class T1> struct SpecializedType{    T1 x1;    T1 x2;};template <class T>class Compare<SpecializedType<T> >{public:    static bool IsEqual(const SpecializedType<T>& lh, const SpecializedType<T>& rh)    {        return Compare<T>::IsEqual(lh.x1 + lh.x2, rh.x1 + rh.x2);    }};
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

这就是三种类型的模板特化, 我们可以这么使用这个Compare类:

   // int    int i1 = 10;    int i2 = 10;    bool r1 = Compare<int>::IsEqual(i1, i2);    // float    float f1 = 10;    float f2 = 10;    bool r2 = Compare<float>::IsEqual(f1, f2);    // double    double d1 = 10;    double d2 = 10;    bool r3 = Compare<double>::IsEqual(d1, d2);    // pointer    int* p1 = &i1;    int* p2 = &i2;    bool r4 = Compare<int*>::IsEqual(p1, p2);    // vector<T>    vector<int> v1;    v1.push_back(1);    v1.push_back(2);    vector<int> v2;    v2.push_back(1);    v2.push_back(2);    bool r5 = Compare<vector<int> >::IsEqual(v1, v2);    // custom template class     SpecializedType<float> s1 = {10.1f,10.2f};    SpecializedType<float> s2 = {10.3f,10.0f};    bool r6 = Compare<SpecializedType<float> >::IsEqual(s1, s2);
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
           

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

猜你喜欢

转载自blog.csdn.net/ugfffj/article/details/86559212