C 模板特化和偏特化

2021-07-04 09:10:46 字數 4568 閱讀 9826

1.引言

c++中的模板分為類模板和函式模板,雖然它引進到c++標準中的時間不是很長,但是卻得到了廣泛的應用,這一點在stl中有著充分的體現。目前,stl在c++社群中得到了廣泛的關注、應用和研究。理解和掌握模板是學習、應用和研究以及擴充stl的基礎。而stl模板例項中又充斥著大量的模板特化和偏特化。

2.模板的定義

(1) 類模板

定義乙個棧的類模板,它可以用來容納不同的資料型別

說明如下:

template class stack ;

上述定義中,template告訴編譯器這是乙個模板,尖括號中的指明模板的引數,可以有乙個或多個,具體實現時由使用者指定,其中template 中的關鍵字class可以用關鍵字typename來代替。

類模板的使用除了要在宣告時指明模板引數外,其餘均與普通的類相同,例如:

stackint_stack;

stackch_stack;

stackstr_stack;

int_stack.push(10);

ch_stack.push(『z』);

str_stack.push(「c++」);

(2)函式模板

假設現在要定義乙個max函式來返回同一型別(這種型別是允許比較的)兩個值的最大者.

templatet mymax(const t& t1,const t& t2)

template 的意義與類模板定義中相同。

模板函式的使用與普通非模板函式使用相同,因為模板函式的引數可以從其傳入引數中解析出來。例如:

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 stack {};

template < >

class stack;

上述定義中template < >告訴編譯器這是乙個特化的模板。

(2) 函式模板的特化

看下面的例子

main()

前面兩個mymax都能返回正確的結果.而第三個卻不能,因為,此時mymax直接比較兩個指標p1 和 p2 而不是其指向的內容.

針對這種情況,當mymax函式的引數型別為const char* 時,需要特化。

template t mymax(const t t1, const t t2)

template <>

const char* mymax(const char* t1,const char* t2)

現在mymax(p1,p2)能夠返回正確的結果了。

4.模板的偏特化

模板的偏特化是指需要根據模板的某些但不是全部的引數進行特化

(1) 類模板的偏特化

例如c++標準庫中的類vector的定義

template class vector ;

template class vector;

這個偏特化的例子中,乙個引數被繫結到bool型別,而另乙個引數仍未繫結需要由使用者指定。

(2) 函式模板的偏特化

嚴格的來說,函式模板並不支援偏特化,但由於可以對函式進行過載,所以可以達到類似於類模板偏特化的效果。

template void f(t); (a)

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

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

如果將(a)稱為基模板,那麼(b)稱為對基模板(a)的過載,而非對(a)的偏特化。c++的標準委員會仍在對下乙個版本中是否允許函式模板的偏特化進行討論。

5.模板特化時的匹配規則

(1) 類模板的匹配規則

最優化的優於次特化的,即模板引數最精確匹配的具有最高的優先權

例子:template class vector; // (a) 普通型

template class vector; // (b) 對指標型別特化

template <> class vector ; // (c) 對void*進行特化

每個型別都可以用作普通型(a)的引數,但只有指標型別才能用作(b)的引數,而只有void*才能作為(c)的引數

(2) 函式模板的匹配規則

非模板函式具有最高的優先權。如果不存在匹配的非模板函式的話,那麼最匹配的和最特化的函式具有高優先權

例子:template void f(t); // (d)

template void f(int, t, double); // (e)

template void f(t*); // (f)

template <> void f(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)我怎麼覺得是呼叫(h)

參考文獻

[1] bjarne stroustrup, the c++ programming language (special edition), addison wesley,2000

[2] nicolai m.josuttis, the c++ standard library – a tutorial and reference ,addison wesley,1999

[3] stanley lippman and josée lajoie ,c++ primier, 3rd edition ,addison wesley longman ,1998

補充:

partial template specialization能夠讓你在模板(template)的所有可能的實體中特化出一組子集.

1.模板的特化(template specialization):

例如,定義如下的乙個模板:

templateclass widget

;然後你可以像下面那樣明確地加以特化:

template<> //注意:template後面的尖括號中不帶任何內容;

class widget;

其中modaldialog和mycontroller是你自己另外定義的類;有了這個widget的特化定義之後,如果你以後定義了widget物件時,編譯器就會使用上述的特化定義,如果定義了其它泛型物件,那麼編譯器就是用原本的泛化定義;這就是模板的特化.

2.partial template specialization(模板偏特化)

模板特化是通過"給模板中的所有模板引數乙個具體的類"的方式來實現的.而模板偏特化則是通過"給模板中的部分模板引數以具體的類,而留下剩餘的模板引數仍然使用原來的泛化定義"的方式來實現的;

比如,就上面的widget類模板的定義來說,有時候想針對任意的window來搭配乙個特定的mycontroller類特化widget,這個時候就需要使用模板偏特化機制了.下面的widget類模板就是widget的偏特化定義:

template//仍然使用原來的泛化定義;

class widget//mycontroller是具體的類,是特化定義;

;這就是乙個偏特化定義;乙個mycontroller類可以搭配任意一種window.

通常在乙個類模板的偏特化定義中,你只會特化某些模板引數而留下其它泛化引數.當你在程式中具體實現上述類模板的時,編譯器會試著找出最匹配的模板定義.這個尋找過程十分複雜精細,允許你以富有創意的方式來進行偏特化.例如,假設你有乙個button類模板,它有乙個模板引數,那麼,你不但可以拿任意的window搭配特定的mycontroller來特化widget,還可以拿任意button搭配特定的mycontroller來偏特化widget:

templateclass widget, mycontroller> //使用任意button搭配具體的類mycontorller

;模板的偏特化能力很強大.當你例項化乙個模板時,編譯器會把目前存在的偏特化模板和全特化模板做比較,並找出其中最合適、最匹配的實現.這樣,靈活性就很大.但是不幸的是,模板的偏特化機制不能用在函式身上,不論成員函式還是非成員函式.

注意:1.雖然你可以全特化類模板中的成員函式,但是你不能偏特化他們;

2.你不能偏特化命名空間級別(namespace-level)的函式(non-member).最接近"命名空間級別模板函式"的偏特化機制就是函式過載,那就意味著你對"函式引數"(而非返回值型別或內部所用型別)有很精緻的特化能力;

3.特化或全特化時,template後面的尖括號中不帶任何內容;

總結:模板特化/全特化是指給每乙個模板引數乙個具體的型別,以具體實現這個模板,而且template後面的尖括號中不帶任何內容;

模板偏特化是指只給部分模板引數乙個具體的型別,來實現這個模板;

c 模板特化和偏特化

定義乙個棧的類模板,它可以用來容納不同的資料型別,說明如下 template class stack 上述定義中,template告訴編譯器這是乙個模板,尖括號中的指明模板的引數,可以有乙個或多個,具體實現時由使用者指定,其中template中的關鍵字class可以用關鍵字typename來代替。類...

C 模板特化和偏特化

使用模板時會遇到一些特殊的型別需要特殊處理,不能 或不希望 直接使用當前的模板版本時,所以此時我們就需要對該型別定義乙個類或函式的特例化版本。例 當使用乙個判斷相等的模板函式時 templatebool isequal t p1,t p2 但是該模板函式在對於字串進行比較時就不能使用了,對於字串我們...

C 模板特化 偏特化

注意 特化時模板引數的先後順序不能變 特化是基於泛化版本進行的 函式模板特化過載與函式過載不衝突 函式模板只能全特化不能偏特化 模板類泛化 templateclass mytest int m func 模板類全特化 template class mytest 模板類偏特化 templateclas...