天天看點

重學C++ (十二) 模闆特化和偏特化一、模闆的定義二、模闆特化三、模闆偏特化四、模闆特化時的比對

一、模闆的定義

1.類模闆

template <class T>
class compare
{
public:
    bool IsEqual(T t1, T t2)
    {
        return t1 == t2;
    }
};

int main()
{
    char str1[] = "Hello";
    char str2[] = "Hello";
    compare<int> c1;
    compare<char *> c2;   
    cout << c1.IsEqual(, ) << endl;        //比較兩個int類型的參數
    cout << c2.IsEqual(str1, str2) << endl;   //比較兩個char *類型的參數
    return ;
}
           

2.函數模闆

bool IsEqual(T t1, T t2)
{
    return t1 == t2;
}

int main()
{
    char str1[] = "Hello";
    char str2[] = "Hello";
    cout << IsEqual(, ) << endl;
    cout << IsEqual(str1, str2) << endl;
    return ;
}
           

二、模闆特化

上述代碼中,比較字元串是否相等,由于傳入的參數是char *類型的,IsEqual函數模闆隻是簡單的比較傳入參數的值,即兩個指針是否相等,是以結果為false。顯然,這與我們的初衷不符。是以,上述模闆需要對char *類型進行特别處理,即特化。

1.類模闆特化

template <> //告訴編譯器這是一個特化的模闆
class compare<char *> //特化(char*)
{
public:
    bool IsEqual(char* t1, char* t2)
    {
        return strcmp(t1, t2) == ;         //使用strcmp比較字元串
    }
};
           

注意,如果是在類特化外部定義成員時,成員之前不能加template<>标記。

另外,我們可以隻特化成員而不特化類,比如vector中,我們可以隻特化push_back操作:

template<>
void vector<const char *>::push_back(const char *const &val)
{
    //...
}
           

類類型vector

2.函數模闆特化

template <> 
bool IsEqual(char* t1, char* t2) //函數模闆特化
{
    return strcmp(t1, t2) == ;
}
           

三、模闆偏特化

1.類模闆的偏特化

當有多個模闆形參時,我們可以隻特化一部分形參而不是全部。

c++标準庫中的類vector的定義就是一個例子:

template <class T, class Allocator>
class vector { // … // };

template <class Allocator>
class vector<bool, Allocator> { //…//};
           

上述例子中,一個參數被綁定到bool類型,而另一個參數仍未綁定需要由使用者指定。

補充一個指針的偏特化:

template <typename T>
class C {...}; //此泛化版本的T可以是任何類型

template <typename T>
class C<T*> {...}; //特化版本,T為指針類型
           

以上特點在STL裡面用的很多,有興趣參見我關于STL疊代器部分的博文。

2.函數模闆的“偏特化”

嚴格來說,函數模闆并不支援偏特化,但由于可以對函數進行重載,是以可以達到類似于類模闆偏特化的效果。

template <class T> void f(T);  (a)
           

根據重載規則,對(a)進行重載

template < class T> void f(T*);  (b)
           

如果将(a)稱為基模闆,那麼(b)稱為對基模闆(a)的重載,而非對(a)的偏特化。

四、模闆特化時的比對

1.類模闆的比對

最優化的優于次特化的,即模闆參數最精确比對的具有最高的優先權

例子:

template <class T> class vector{//…//}; // (a)  普通型
template <class T> class vector<T*>{//…//};  // (b) 對指針類型特化
template <>   class vector <void*>{//…//};  // (c) 對void*進行特化
           

每個類型都可以用作普通型(a)的參數,但隻有指針類型才能用作(b)的參數,而隻有void*才能作為(c)的參數

2.函數模闆的比對

非模闆函數具有最高的優先權。如果不存在比對的非模闆函數的話,那麼最比對的和最特化的函數具有高優先權

例子:

template <class T> void f(T);  // (d)
template <class T> void f(int, T, double); // (e)
template <class T> void f(T*);  // (f)
template <> void f<int> (int) ; // (g)
void f(double);  // (h)
bool b;
int i;
double d;
f(b); // 以 T = bool 調用 (d)
f(i,,d) // 以 T = int 調用(e)
f(&i) ; // 以 T = int* 調用(f)
f(d);  //  調用(g)