模板特化和偏特化
C++中的模板分為類模板和函數模板
·模板的特化
(1)類模板特化
有時為了需要,針對特定的類型,需要對模板進行特化,也就是特殊處理.例如,stack類模板針對bool類型,因為實際上bool類型只需要一個二進制位,就可以對其進行存儲,使用一個字或者一個字節都是浪費存儲空間的.
template <class T>
class stack {};
template<>
class stack<bool>
{
//…//
};
上述定義中template < >告訴編譯器這是一個特化的模板。并且在聲明特化模板之前一定要有非特化的聲明!并且兩個類的名字是一樣的!
(2)函數模板的特化
看下面的例子
int 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);
return 0;
}
前面兩個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); // 調用(h)