特化 偏特化

摘要:本文通過例子介紹了在 C++標準庫中廣泛使用的模板特化和偏特化,並指出了模板特化和偏特化的定義規則和應用規則。
關鍵詞:模板、特化、偏特化
1.引言
C++中的模板分爲類模板和函數模板,雖然它引進到C++標準中的時間不是很長,但是卻得到了廣泛的應用,這一點在STL中有着充分的體現。目前,STL 在C++社區中得到了廣泛的關注、應用和研究。理解和掌握模板是學習、應用和研究以及擴充STL的基礎。而STL模板實例中又充斥着大量的模板特化和偏特 化。
2.模板的定義
(1) 類模板
定義一個棧的類模板,它可以用來容納不同的數據類型
說明如下:
template <class T>
class stack {
private:
   list* top;
public:
   stack();
   stack(const stack&);
   ~stack();
   void push(T&);
   T& pop();
   //…
};
上述定義中,template告訴編譯器這是一個模板,尖括號中的<class T >指明模板的參數,可以有一個或多個,具體實現時由用戶指定,其中template <class T >中的關鍵字class可以用關鍵字typename來代替。
類模板的使用除了要在聲明時指明模板參數外,其餘均與普通的類相同,例如:
stack<int> int_stack;
stack<char> ch_stack;
stack<string> str_stack;
int_stack.push(10);
ch_stack.push(‘z’);
str_stack.push(“c++”);
(2)   函數模板
假設現在要定義一個max函數來返回同一類型(這種類型是允許比較的)兩個值的最大者.
template<class T>
T mymax(const T& t1,const T& t2)
{ return t1 < t2 ? t2 : t1; }
template <class T>的意義與類模板定義中相同。
模板函數的使用與普通非模板函數使用相同,因爲模板函數的參數可以從其傳入參數中解析出來。例如:
int highest = mymax(5,10);
char c = mymax(‘a’, ’z’);
mymax(5,10)解析出模板函數參數爲int, mymax(‘a’, ’z’)解析出模板函數的參數爲char。
3.模板的特化
(1)   類模板特化
有時爲了需要,針對特定的類型,需要對模板進行特化,也就是特殊處理.例如,stack類模板針對bool類型,因爲實際上bool類型只需要一個二進制位,就可以對其進行存儲,使用一個字或者一個字節都是浪費存儲空間的.
template <class T>
class stack {};
template < >
class stack<bool> { //…// };
上述定義中template < >告訴編譯器這是一個特化的模板。
(2) 函數模板的特化
看下面的例子
main()
{
   int highest = mymax(5,10);
   char c = mymax(‘a’, ’z’);
   const char* p1 = “hello”;
   const char* p2 = “world”;
   const char* p = mymax(p1,p2);
}
前面兩個mymax都能返回正確的結果.而第三個卻不能,因爲,此時mymax直接比較兩個指針p1 和 p2 而不是其指向的內容.
針對這種情況,當mymax函數的參數類型爲const char* 時,需要特化。
template <class T>
T mymax(const T t1, const T t2)
{
    return t1 < t2 ? t2 : t1;
}

template <>
const char* mymax(const char* t1,const char* t2)
{
    return (strcmp(t1,t2) < 0) ? t2 : t1;
}
現在mymax(p1,p2)能夠返回正確的結果了。
4.模板的偏特化
模板的偏特化是指需要根據模板的某些但不是全部的參數進行特化
(1) 類模板的偏特化
例如c++標準庫中的類vector的定義
template <class T, class Allocator>
class vector { // … // };
template <class Allocator>
class vector<bool, Allocator> { //…//};
這個偏特化的例子中,一個參數被綁定到bool類型,而另一個參數仍未綁定需要由用戶指定。
(2) 函數模板的偏特化
   嚴格的來說,函數模板並不支持偏特化,但由於可以對函數進行重載,所以可以達到類似於類模板偏特化的效果。
   template <class T> void f(T);   (a)
   根據重載規則,對(a)進行重載
   template < class T> void f(T*);   (b)
   如果將(a)稱爲基模板,那麼(b)稱爲對基模板(a)的重載,而非對(a)的偏特化。C++的標準委員會仍在對下一個版本中是否允許函數模板的偏特化進行討論。
5.模板特化時的匹配規則
(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,42,d) // 以 T = int 調用(e)
f(&i) ; // 以 T = int* 調用(f)
f(d);   //   調用(g)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章