模板為C++提供了鴨子類型(Duck typing)的特性恢筝。所謂鴨子類型元扔,指的是代碼關(guān)注的不是對(duì)象的類型本身,而是它被如何使用的。例如丑慎,在使用鴨子類型的語言中,我們編寫一個(gè)函數(shù)可以接受一個(gè)任意類型的對(duì)象坡倔,只要它有走抄肖、游泳和嘎嘎叫方法。至于客戶給它傳入的是一只真正的鴨子许蓖,或是也能走蝴猪、游泳和嘎嘎叫的其它類型對(duì)象,都沒有關(guān)系膊爪。但是如果傳入的對(duì)象中沒有這些需要被調(diào)用的方法自阱,就將引發(fā)一個(gè)錯(cuò)誤。
" When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck. - James Whitcomb Riley, 1849-1916"
我們看下面這個(gè)例子:
template<typename T>
T max(const T& t1米酬, const T& t2)
{
return (t1 > t2)? t1 : t2;
}
對(duì)max
沛豌,只約束入?yún)㈩愋蚑支持>
比較運(yùn)算,而不關(guān)心它的具體類型淮逻。例如我們可以為max
傳入int
琼懊、float
或者是實(shí)現(xiàn)了了opertator >
的任何對(duì)象。
直到現(xiàn)在爬早,C++中模板對(duì)入?yún)⒌募s束都是通過對(duì)入?yún)⒌氖褂梅绞絹黼[式體現(xiàn)的哼丈。而有的語言卻可以顯示約束。例如對(duì)于如下Haskell代碼:
max' :: (Ord a) => a -> a -> a
max' x y
| x > y = x
| otherwise = y
如上max
的定義前面通過函數(shù)聲明:max' :: (Ord a) => a -> a -> a
約束了入?yún)⒌念愋?code>a必須滿足Ord
類型類的約束筛严。類型類用于規(guī)范一組類型應(yīng)該滿足的特征醉旦,例如Ord
要求滿足它的類型必須能夠進(jìn)行標(biāo)準(zhǔn)的比較操作,如<
桨啃、>
车胡、<=
、>=
等照瘾。
C++17標(biāo)準(zhǔn)有可能會(huì)引入concept特性用來支持上述haskell中對(duì)類型特征進(jìn)行顯示約束的能力匈棘。顯示化類型約束可以讓代碼更容易被理解,讓編譯器可以更準(zhǔn)確的報(bào)告錯(cuò)誤或者對(duì)代碼更好地做出優(yōu)化析命,同時(shí)也可以讓IDE對(duì)語言更好地支持主卫。
鴨子類型為程序的書寫帶來了很多便利性,基本上動(dòng)態(tài)語言(Python鹃愤、Ruby)以及擁有類型推導(dǎo)的靜態(tài)語言(C++簇搅、Haskell、Scala)都有這個(gè)特性软吐。區(qū)別在于動(dòng)態(tài)語言一般是在運(yùn)行期發(fā)現(xiàn)類型不滿足約束瘩将,而靜態(tài)語言通過強(qiáng)大的類型推導(dǎo)可以在編譯期就發(fā)現(xiàn)錯(cuò)誤。
回到最后,我們思考下姿现,如果把C++模板元編程當(dāng)做一門獨(dú)立的語言肠仪,它自身是否支持鴨子類型呢?
答案很明確建钥,雖然模板為“運(yùn)行時(shí)C++”提供了鴨子類型的能力藤韵,但模板元編程自身卻不支持鴨子類型。
例如下面的元函數(shù)明確要求其入?yún)⒌男蛣e為類型熊经,所以你可以這樣使用SizeOf<int>
泽艘。但是一旦你傳入一個(gè)數(shù)值SizeOf<5>
,它就會(huì)報(bào)錯(cuò)镐依。
template<typename T>
struct SizeOf
{
using Result = __int(sizeof(T));
}匹涮;
我們之前總結(jié)過,模板可以操作的計(jì)算對(duì)象大體可以分為數(shù)值和類型兩大類槐壳,一旦我們把模板當(dāng)做編譯期函數(shù)來看然低,就會(huì)發(fā)現(xiàn)它是強(qiáng)類型的。一個(gè)模板聲明其入?yún)⑹菙?shù)值型务唐,就不能接收類型作為入?yún)Ⅵㄈ粒粗嗳唬∵@就是為何我們?yōu)榱颂岣咴瘮?shù)的組合復(fù)用能力枫笛,將所有的數(shù)值也封裝成了類型吨灭。我們統(tǒng)一模板元編程的計(jì)算對(duì)象類型,就相當(dāng)于把一切都變成了鴨子刑巧,間接地也得到了鴨子類型的好處喧兄。
最后,我們單獨(dú)看待模板元編程的時(shí)候啊楚,它相當(dāng)是一門解釋型語言吠冤!C++編譯器直接面對(duì)模板元編程的源代碼進(jìn)行編譯期計(jì)算,這時(shí)我們可以將C++編譯器看做是模板元編程的解釋器恭理,它一邊解釋一邊執(zhí)行拯辙,解釋結(jié)束之時(shí)也是程序執(zhí)行完畢之時(shí)。有趣吧颜价?在這個(gè)角度看模板元編程反而更像是一門腳本語言薄风。