1. 程式人生 > >C++模板 全特化、偏特化

C++模板 全特化、偏特化

C++模板 全特化、偏特化

模板

模板的定義:模板就是實現程式碼重用機制的一種工具,它可以實現型別引數化,即把型別定義為引數, 從而實現了真正的程式碼可重用性。
模版可以分為兩類,一個是 函式模版 ,另外一個是 類模版

函式模板,類模板樣例:

/**
 * 作者:lyn
 * 時間:2018.10.30
 * 該程式用來演示函式模板和類模板
 */
#include <iostream>

using namespace std;

//模板函式
template<typename T>
void add(T num1, T num2) {
        cout << num1 << " + " << num2 << " = "<< num1 + num2 << endl;
}

//模板類
template<typename T>
class Test_Class {
public:
        static void multi(T num1, T num2) {
                cout << num1 << " * " << num2 << " = "<< num1 * num2 << endl;
        }
};

int main(){
        //Test 1
        int num1 = 1;
        int num2 = 2;
        add<int>(num1, num2);
        Test_Class<int>::multi(num1, num2);
        //Test 2
        double num3 = 3.1;
        double num4 = 4.2;
        add<double>(num3, num4);
        Test_Class<double>::multi(num3, num4);
        return 0;
}

在這裡插入圖片描述
函式模板是可以被過載的(類模板不能被過載),也就是說允許存在兩個同名的函式模板,還可以對它們進行例項化,使它們具有相同的引數型別。

函式模板過載樣例:

/**
 * 作者:lyn
 * 時間:2018.10.30
 * 該程式用來掩飾函式模板的過載
 */
#include <iostream>

using namespace std;

//函式模板
template <typename T>
int fun(T){
        return 1;
}
//函式模板的過載
template <typename T>
int fun(T*){
        return 2;
}

int main(){
        cout << fun<int*>((int*)0) << endl;
        cout << fun<int>((int*)0) << endl;
        return 0;
}

在這裡插入圖片描述

特化

前面提到函式模板能被過載,而類模板不可以,我們可以通過特化來實現相似的效果,從而可以透明地獲得具有更高效率的程式碼。
特化也分為了兩種,全特化和偏特化。

  • 不能將特化和過載混為一談
    全特化和偏特化都沒有引入一個全新的模板或者模板例項。它們只是對原來的泛型(或者非特化)模板中已經隱式宣告的例項提供另一種定義。
    在概念上,這是一個相對比較重要的現象,也是特化區別於過載模板的關鍵之處。
全特化

全特化是模板的一個唯一特例,指定的模板實參列表必須和相應的模板引數列表一一對應。
我們不能用一個非型別值來替換模型別引數。但是如果模板引數具有預設模板實參,那麼用來題還實參就是可選的。

全特化類樣例:

/**
 * 作者:lyn
 * 時間:2018.10.30
 * 該程式用來演示全特化類
 */
#include <iostream>
using namespace std;

template<typename T1, typename T2>
class A{
        public:
                void function(T1 value1, T2 value2){
                        cout<<"value1 = "<<value1<<endl;
                        cout<<"value2 = "<<value2<<endl;
                }
};

template<>
class A<int, double>{ // 型別明確化,為全特化類
        public:
                void function(int value1, double value2){
                        cout<<"intValue = "<<value1<<endl;
                        cout<<"doubleValue = "<<value2<<endl;
                }
};

int main(){
        A<int, double> a;
        a.function(12, 12.3);
        return 0;
}                                                                                                                     

在這裡插入圖片描述

偏特化

偏特化感覺像是介於普通模板和全特化之間,只存在部分的型別明確化,而非將模板唯一化。
再次劃重點 函式模板不能被偏特化

偏特化類樣例:

/**
 * 作者:lyn
 * 時間:2018.10.30
 * 該程式用來演示偏特化類
 */
#include <iostream>
using namespace std;

template<typename T1, typename T2>
class A{
        public:
                void function(T1 value1, T2 value2){
                        cout<<"value1 = "<<value1<<endl;
                        cout<<"value2 = "<<value2<<endl;
                }
};

template<typename T>
class A<T, double>{ // 部分型別明確化,為偏特化類
        public:
                void function(T value1, double value2){
                        cout<<"Value = "<<value1<<endl;
                        cout<<"doubleValue = "<<value2<<endl;
                }
};

int main(){
        A<char, double> a;
        a.function('a', 12.3);
        return 0;
}

在這裡插入圖片描述

偏特化的特殊例子
//這段程式碼是STL原始碼中的一部分
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;
};
/*
 * 偏特化版本,我們可以看到他的唯一不同之處就是T*,這也是偏特化的一種
 */
template <class T>
struct iterator_traits<T*> {
  typedef random_access_iterator_tag iterator_category;
  typedef T                          value_type;
  typedef ptrdiff_t                  difference_type;
  typedef T*                         pointer;
  typedef T&                         reference;
};
重點總結
  1. 類模板和函式模板都可以被全特化;
  2. 類模板能偏特化,不能被過載;
  3. 函式模板全特化,不能被偏特化。

模板類呼叫優先順序

對主版本模板類、全特化類、偏特化類的呼叫優先順序從高到低進行排序是:
全特化類>偏特化類>主版本模板類
這樣的優先順序順序對效能也是最好的。