前面我們介紹了C++模板元編程的基礎(chǔ)知識(shí)。我們將模板元編程的計(jì)算對(duì)象統(tǒng)一到類型上,引入了元函數(shù)的概念。元函數(shù)是模板元編程的基礎(chǔ)構(gòu)件,它支持默認(rèn)參數(shù),支持高階函數(shù),支持柯里化,遵守不可變性,具有惰性特征。此外我們還介紹了在模板元編程中做計(jì)算控制的模式匹配和遞歸的相關(guān)技巧。
在示例代碼中,我們完成了幾個(gè)模板元編程的基礎(chǔ)元函數(shù):IntType,BoolType,Value,Print,IsEqual,IfThenElse等等,并且對(duì)它們用宏進(jìn)行了封裝,分別是__int(),__bool(),__value(),__print(),__is_eq(),__if()。后文在使用的時(shí)候,對(duì)于某一用宏封裝過的元函數(shù),會(huì)提到“元函數(shù)Value”,可能也會(huì)提成“元函數(shù)__value()”,請(qǐng)注意它們是相同的。
在前面的介紹中,我們一直將C++模板元編程看做是一門獨(dú)立的圖靈完備的純函數(shù)式語言。雖然C++模板元編程和我們熟識(shí)的運(yùn)行期C++無論在語法還是計(jì)算模型上都有較大的差異,但他們卻能最緊密無縫地集成在一起。有了模板元編程,我們就可以把C++看成是一門兩階段語言。

第一階段發(fā)生在C++編譯期前段,這時(shí)可以看做是C++模板元編程的天下。此時(shí),C++相當(dāng)于一門純函數(shù)式的解釋型語言,編譯器在此時(shí)充當(dāng)了解釋器的角色,直接面向C++源代碼進(jìn)行解釋執(zhí)行。我們知道對(duì)于代碼最全的元信息就存在于源代碼自身中,所以解釋型語言所謂反射或者自省的能力都非常的強(qiáng),這也是C++模板元編程擁有強(qiáng)大能力的原因之一??蚣芎蛶斓拈_發(fā)往往離不開語言自身擁有的反射能力。C++模板元編程帶來的這種反射能力,和運(yùn)行期C++的RTTI技術(shù)本質(zhì)并不相同,它更加的強(qiáng)大且不會(huì)帶來運(yùn)行時(shí)開銷。STL中的type_traits庫,利用模板元編程技術(shù)定義了非常多的編譯期反射工具,可以直接供大家使用。
第一階段C++模板元編程的另一特殊性在于它的計(jì)算對(duì)象:類型和常量,它們是構(gòu)成運(yùn)行期C++的基本元素。因此模板元編程可以看做是運(yùn)行期C++的代碼生成器。當(dāng)?shù)谝浑A段結(jié)束后,C++編譯器恢復(fù)我們熟識(shí)的角色,針對(duì)第一階段的結(jié)果代碼進(jìn)行編譯,產(chǎn)生可以運(yùn)行的C++程序。正是模板元編程這種可以充當(dāng)運(yùn)行期C++代碼生成器的能力,使得它成為構(gòu)造內(nèi)部DSL的強(qiáng)大工具。
C++在編譯期之前還有一個(gè)預(yù)處理階段。預(yù)處理期可以利用宏完成各種代碼生成,Boost中還專門有一個(gè)關(guān)于預(yù)處理的工具庫preprocessor,用于在預(yù)處理期進(jìn)行數(shù)值運(yùn)算及代碼生成,甚至還定義了預(yù)處理期的數(shù)據(jù)結(jié)構(gòu)和算法。雖然預(yù)處理技術(shù)也是一項(xiàng)非常有用的工具,但由于其原理僅是文本替換,并不做真正的運(yùn)算,所以理論上并非是圖靈完備的,因此我們?cè)谏蠄D中并未將其列入。
由于C++的模板元編程能力是在C++語言引入模板特性后被意外發(fā)現(xiàn)的,所以不像別的經(jīng)過預(yù)先良好設(shè)計(jì)的函數(shù)式語言那樣語法優(yōu)美,功能完備。通過前面的例子確實(shí)也看到它的很多寫法相比Haskell要繁瑣的多,而且功能上也要差很多。在C++11出現(xiàn)之前,標(biāo)準(zhǔn)上對(duì)模板元編程的支持還存在一些大的缺陷,而且不同編譯器對(duì)模板元編程的支持也不太統(tǒng)一。另外我們也看到,模板元編程操作IO的能力非常的差,這導(dǎo)致了模板元編程的問題定位變得困難。
得益于近些年C++標(biāo)準(zhǔn)以及主流編譯器對(duì)C++編譯期計(jì)算支持得越來越完備,使得模板元編程相比以前要更加方便和完善。雖然如此,由于歷史原因,它仍舊無法和一門真正經(jīng)過良好設(shè)計(jì)的語言相比。但由于它內(nèi)置于C++,使得它和運(yùn)行期C++的結(jié)合上有著天然無法替代的優(yōu)勢(shì),這也是我們要學(xué)習(xí)它的原因。不要相信類似 “python + 傳統(tǒng)C++” 的說法,否則你就基本喪失了構(gòu)造靈活高效的C++程序庫和框架的能力。想要成為一名專業(yè)的C++程序員,熟悉模板元編程是必須的。