Overloading vs. Specialization
在C++中有class templates 和function templates,這兩種模版有很多區(qū)別,最重要的區(qū)別就是重載(overloading):
普通的C++類不能重載,當(dāng)然類模版也不能重載;相反,普通函數(shù)可以重載,函數(shù)模版也能重載。這再正常不過,看下面的代碼:
?1?//
?Example?1:?Class?vs.?function?template,?and?overloading?
?2?//
?3?
?4?//?A?class?template
?5?template<class?T>?class?X?{?/*...*/?};??????//
?(a)
?6?
?7?//?A?function?template?with?two?overloads
?8?template<class?T>?void?f(?T?);??????????????//?(b)
?9?template<class?T>?void?f(?int,?T,?double?);?//
?(c)
10?
像上面未特化的模板通常叫做base templates。當(dāng)然,base templates能夠被特化,在特化這一點(diǎn)上
class templates 和function templates有很大的區(qū)別:一個(gè)class template 能夠被partially specialized and/or
fully specialized,一個(gè)function template只能被fully specialized,但是由于function templates能夠重載我們可以通過重載來實(shí)現(xiàn)和partially specialized 相當(dāng)?shù)墓δ堋O旅娴拇a說明了這些區(qū)別:
?1?//
?Example?1,?continued:?Specializing?templates?
?2?//
?3?
?4?//?A?partial?specialization?of?(a)?for?pointer?types?
?5?template<class?T>?class?X<T*>?{?/*...*/
?};
?6?
?7?//?A?full?specialization?of?(a)?for?int?
?8?template<>?class?X<int>?{?/*...*/
?};
?9?
10?//
?A?separate?base?template?that?overloads?(b)?and?(c)?
11?//
?--?NOT?a?partial?specialization?of?(b),?because?
12?//
?there's?no?such?thing?as?a?partial?specialization?
13?//?of?a?function?template!?
14?template<class?T>?void?f(?T*?);?????????????//
?(d)
15?
16?//?A?full?specialization?of?(b)?for?int?
17?template<>?void?f<int>(?int?);??????????????//
?(e)
18?
19?//
?A?plain?old?function?that?happens?to?overload?with?
20?//
?(b),?(c),?and?(d)?--?but?not?(e),?which?we'll?
21?//?discuss?in?a?moment?
22?void?f(?double?);???????????????????????????//
?(f)
23?
根據(jù)函數(shù)重載解析規(guī)則:
?1?//
?Example?1,?continued:?Overload?resolution?
?2?//?
?3?
bool?b;?
?4?int
?i;?
?5?double
?d;
?6?
?7?f(?b?);????????//?calls?(b)?with?T?=?bool?
?8?f(?i,?42,?d?);?//?calls?(c)?with?T?=?int?
?9?f(?&i?);???????//?calls?(d)?with?T?=?int?
10?f(?i?);????????//?calls?(e)?
11?f(?d?);????????//?calls?(f)
上面說的這些其實(shí)都是很簡(jiǎn)單的情況,大多數(shù)人很容易就能明白,下面的才是容易讓人弄混的:
1.考慮如下代碼:
?1?//
?Example?2:?Explicit?specialization?
?2?//?
?3?template<class?T>?//?(a)?a?base?template?
?4?void
?f(?T?);
?5?
?6?template<class?T>?//?(b)?a?second?base?template,?overloads?(a)?
?7?void?f(?T*?);?????//
?????(function?templates?can't?be?partially?
?8???????????????????//?????specialized;?they?overload?instead)
?9?
10?template<>????????//?(c)?explicit?specialization?of?(b)?
11?void?f<>(int*
);
12?
13?//?...
14?
15?int?*
p;?
16?f(?p?);???????????//?calls?(c)
最后一行的結(jié)果像大多數(shù)人所期望的一樣,問題是:為什么期望是這個(gè)結(jié)果?
如果你期望的原因是錯(cuò)誤的,接下來的一定會(huì)讓你好奇。也許你會(huì)說:"我為int*寫了一個(gè)特化版本,f(p)當(dāng)然會(huì)調(diào)用c",不幸的是,這正是錯(cuò)誤的原因!!!
2.再考慮下面的代碼:
?1?//
?Example?3
?2?//?
?3?template<class?T>?//?(a)?same?old?base?template?as?before?
?4?void
?f(?T?);
?5?
?6?template<>????????//?(c)?explicit?specialization,?this?time?of?(a)
?7?void?f<>(int*
);
?8?
?9?template<class?T>?//?(b)?a?second?base?template,?overloads?(a)?
10?void?f(?T*
?);
11?
12?//?...
13?
14?int?*
p;?
15?f(?p?);???????????//
?calls?(b)!?overload?resolution?ignores?
16???????????????????//
?specializations?and?operates?on?the?base?
17???????????????????//?function?templates?only
如果這個(gè)結(jié)果讓你感到驚奇,那就對(duì)了!很多人都會(huì)感到驚奇!
理解這個(gè)的關(guān)鍵是:Specializations don't overload,only the base templates overload.
重載解析僅僅選擇base template(或者nontemplate function,如果有的話),只有當(dāng)編譯器已經(jīng)決定了哪個(gè)
base template將會(huì)被選擇,編譯器才會(huì)繼續(xù)往下尋找適合的特化版本,如果找到了就使用那個(gè)特化版本。
最后,應(yīng)當(dāng)避免特化函數(shù)模板,也要避免重載函數(shù)模板(nontemplate function的重載當(dāng)然沒問題)。如果一定要這樣,可以使用如下方法模擬函數(shù)模板的偏特化:
?1?//base?template?class,?
?2?template?<class?T>
?3?
struct?FuncImpl?{
?4?????//users,?go?ahead?and?specialize?this
?5?????static?int?apply(const?T?&
t)?{
?6?????????return?0
;
?7?
????}
?8?
};
?9?
10?//partial?specialazation?for?int
11?template?<>
12?struct?FuncImpl<int>
?{
13?????static?int?apply(int
?t)?{
14?????????return?1
;
15?
????}
16?
};
17?
18?//partial?specialazation?for?T*
19?template?<class?T>
20?????struct?FuncImpl<T?*>
?{
21?????static?int?apply(T?*
t)?{
22?????????return?2
;
23?
????}
24?
};
25?
26?//users,?don't?touch?this!
27?template?<class?T>
28?int?func(const?T?&
t)?{
29?????return?FuncImpl<T>
::apply(t);
30?
}
31?
32?int?i?=?10
,?r;
33?r?=?func('c');?//r?=?0
34?r?=?func(8);?//r?=?1
35?r?=?func(&i);?//r?=?2