C++11 模板元編程 - 前言


熟悉C++的程序員都知道,C++是一門多范式編程語言,支持面向過程、面向?qū)ο蟆⒎盒途幊桃约昂瘮?shù)式編程范式。然而提到C++模板元編程,在很多人心里這卻是C++里的黑魔法:它很難學(xué)習(xí),一旦進(jìn)入這個(gè)領(lǐng)域曾經(jīng)那些熟悉的東西(if,for...)都不再靈驗(yàn);它很強(qiáng)大,但現(xiàn)實(shí)中卻鮮見有人用它來解決實(shí)際問題,除過偶爾在一些編碼練習(xí)中被某些C++狂熱粉當(dāng)做奇淫巧技拿出來秀秀肌肉。

其實(shí)模板元編程是C++所支持的一種非常強(qiáng)大的計(jì)算能力,它是使用C++開發(fā)高質(zhì)量庫和框架所離不開的一項(xiàng)武器。

掌握C++模板元編程,至少可以在以下場合幫助到你:

  • 實(shí)現(xiàn)高擴(kuò)展性,并且兼具高性能的庫
  • 實(shí)現(xiàn)靈活且易于使用的框架
  • 實(shí)現(xiàn)基于C++的內(nèi)部DSL(Domain Specific Language)
  • 幫助更深入地理解并使用模板和泛型編程,更好地去使用C++ STL庫中的高級特性

如果你是一個(gè)C++的庫或框架的開發(fā)者,了解和掌握一些模板元編程的知識,可以讓你的作品更易于擴(kuò)展、擁有更易用的接口,甚至更高的運(yùn)行時(shí)效率。而即使你只使用C++設(shè)計(jì)和開發(fā)應(yīng)用程序,了解模板元編程也會(huì)幫助你更好的去使用STL庫的各種特性,幫助你的局部設(shè)計(jì)做的更加漂亮。

實(shí)際上C++模板元編程技術(shù)已經(jīng)滲透在我們?nèi)粘J褂玫母鞣N庫和框架中,例如我們最常使用的STL庫以及各種xUnit測試框架和mock框架。可以說,模板元編程是中級C++程序員邁向高級的必經(jīng)之路!

然而現(xiàn)實(shí)是,C++模板元編程的學(xué)習(xí)之旅卻并不平坦。

一方面,由于C++模板元編程的本質(zhì)是函數(shù)式編程,熟練掌握并使用函數(shù)式編程的程序員比較小眾,絕大多數(shù)程序員初次進(jìn)入這個(gè)領(lǐng)域時(shí)面對模式匹配、遞歸和不可變性時(shí)都會(huì)手足無措。另一方面,由于C++的模板元編程能力是被意外發(fā)現(xiàn)的,不像別的函數(shù)式編程語言經(jīng)過良好的設(shè)計(jì),所以C++的這種函數(shù)式計(jì)算能力天生存在著各種缺陷,直到C++11標(biāo)準(zhǔn)才開始逐漸完善起來。在之前很多重要特性都靠很繞的方式去迂回實(shí)現(xiàn),增加了學(xué)習(xí)的難度。

另外,市面上介紹模板元編程的書和資料也乏善可陳,以下的書相對還不錯(cuò),但對于模板元編程的介紹仍舊存在一些問題:

  • 《C++ Templates Complete》
    介紹C++模板知識最全面的一本書,涉及到了模板各個(gè)方面的基礎(chǔ)知識和應(yīng)用技巧。由于元編程并不是此書重點(diǎn),所以僅有短短一章列舉了一些利用模板元編程做數(shù)值計(jì)算的例子。現(xiàn)實(shí)中使用模板元編程單純做數(shù)值計(jì)算的場合并不多,模板元編程更大的價(jià)值在于做類型計(jì)算和代碼生成,書中卻涉及甚少。

  • 《Modern C++ Design》
    介紹如何使用模板進(jìn)行C++高階設(shè)計(jì)的一本書。介紹了TypeLists的概念,作為一種重要的編譯時(shí)數(shù)據(jù)結(jié)構(gòu),是元編程的基礎(chǔ)。但遺憾作者并沒有明確的提出元編程的概念,也沒有對C++編譯時(shí)的運(yùn)算特征進(jìn)行總結(jié)和提煉。最后由于此書基于的C++ 98標(biāo)準(zhǔn)對于模板以及編譯期類型計(jì)算支持上的欠缺,書中介紹的不少實(shí)現(xiàn)比較迂回復(fù)雜。

  • 《C++模板元編程》
    正式介紹C++模板元編程的一本書,引入了元函數(shù)的概念。通過對模板計(jì)算的規(guī)范化,發(fā)揮了編譯期元函數(shù)可組合的優(yōu)勢。遺憾的是,此書只能算是boost中mpl庫的用戶手冊,基本上是在講mpl庫的用戶接口和使用方法,沒有涉及庫的實(shí)現(xiàn)細(xì)節(jié)。現(xiàn)實(shí)中我們采用元編程解決問題,一般不會(huì)引用boost這么重的庫,往往只會(huì)在某一局部借鑒類似的設(shè)計(jì)技巧。所以對于元編程來說,授之以漁的意義遠(yuǎn)大于授之以魚。另外由于boost mpl庫中用了大量C++預(yù)處理期代碼生成技術(shù),導(dǎo)致通過閱讀mpl源碼去掌握模板元編程的同學(xué)一上來就陷入到一堆宏中,對于學(xué)習(xí)元編程增加了非常多的干擾因素。

基于以上原因,我基于C++11標(biāo)準(zhǔn)實(shí)現(xiàn)了一個(gè)模板元編程的基礎(chǔ)庫:TLP (https://github.com/MagicBowen/tlp),然后再通過本手冊來為大家全面介紹C++模板元編程的基本知識和使用技巧。

TLP庫包含以下內(nèi)容:

  • 基本的編譯期數(shù)據(jù)類型和算法;
  • 基本的編譯期數(shù)據(jù)結(jié)構(gòu)TypeList,以及針對它的各種基本算法函數(shù):length、append、erase、replace、unique、belong、comb...
  • 基于TypeList的各種高階函數(shù),如 any,all,sort、transform、map,filter,fold...
  • 輔助模板元編程的常用函數(shù),如 __is_eq(),__if(),__print() ...
  • 一些有用的編譯期Traits工具,如 IsBaseOf,IsConvertible,IsBuiltIn...
  • 一些常用的元編程模式,如 “元函數(shù)轉(zhuǎn)發(fā)”等;
  • 一個(gè)面向模板元編程的測試框架,用它描述的所有測試用例執(zhí)行在C++的編譯期,我們使用它來對TLP進(jìn)行測試;

除此之外,TLP庫中還包含了如下示例代碼,用來演示如何在現(xiàn)實(shí)場景中應(yīng)用好模板元編程和TLP庫:

  • 示范了如何使用模板元編程做純編譯期計(jì)算,完成一個(gè)自動(dòng)數(shù)三角形的程序;
  • 示范了如何使用模板元編程技術(shù)來實(shí)現(xiàn)代碼生成,自動(dòng)創(chuàng)建visitor設(shè)計(jì)模式;
  • 示范了如何使用模板元編程技術(shù)來實(shí)現(xiàn)一個(gè)DSL,用于描述并生成有限狀態(tài)機(jī);

上面提到的TypeList以及使用代碼生成來創(chuàng)建visitor設(shè)計(jì)模式的原創(chuàng)者是《Modern C++ Design》的作者Andrei Alexandrescu。在TLP中我用C++11對TypeList及其算法進(jìn)行了改寫,并進(jìn)行了高階函數(shù)的擴(kuò)展。得益于C++11標(biāo)準(zhǔn)對模板元編程的更好支持,新的實(shí)現(xiàn)比起原來的更加清晰和簡潔。

示例代碼中利用模板元編程創(chuàng)建有限狀態(tài)機(jī)DSL的設(shè)計(jì)最初來自于《C++模板元編程》一書,為了讓其更好被理解,我對例子以及代碼進(jìn)行了較大的改編。

除了上面的例子,本手冊中還介紹了我自己開發(fā)的針對C++模塊和子系統(tǒng)FT(Functional Test)級別的測試框架dates,展示了它如何使用模板元編程來進(jìn)行類型萃取、類型選擇以及類型校驗(yàn),最終使得框架變得更易用、更高效以及更安全。這些技巧可以幫助到大家更好地使用模板元編程去解決現(xiàn)實(shí)問題。

最后,TLP庫自身的測試通過一個(gè)原創(chuàng)的C++模板元編程測試框架。該框架專門針對C++編譯期計(jì)算進(jìn)行測試,它的用法和常見的xUnit測試框架類似,但有趣的是使用該框架描述的所有測試用例的執(zhí)行發(fā)生在C++編譯期。本文會(huì)專門介紹該框架的一些實(shí)現(xiàn)細(xì)節(jié)。


C++模板元編程當(dāng)年被提出來的時(shí)候,函數(shù)式編程還沒有像今天這樣被更多的人所了解和接受,當(dāng)時(shí)的C++標(biāo)準(zhǔn)和編譯器對模板和編譯期計(jì)算的支持也存在著很多缺陷。然而到了今天,很多事情發(fā)生了變化!本文的讀者最好能夠有一些函數(shù)式編程的基礎(chǔ),了解C++模板的基本用法,熟悉一些C++11標(biāo)準(zhǔn)的內(nèi)容。當(dāng)然文中所有用的到模板技術(shù)、C++11標(biāo)準(zhǔn)和涉及到的函數(shù)式編程概念也都會(huì)專門介紹和說明。

如果你從來沒有接觸過C++模板元編程,那么最好從一開始就把它當(dāng)做一門全新的語言去學(xué)習(xí),從頭掌握C++中這種不一樣的計(jì)算模型和語法。這種新的語言和我們熟識的運(yùn)行期C++在語法和計(jì)算模型上都有較大的差異,但它的優(yōu)勢在于能和運(yùn)行期C++緊密無縫地結(jié)合在一起,無論是在提高程序可擴(kuò)展性還是提高程序運(yùn)行效率上,都能創(chuàng)造出非常不可思議的效果來。希望通過本手冊,可以讓更多的人掌握C++模板元編程這一設(shè)計(jì)利器,在適合的場合下以更有效、更酷的方式去解決問題。

文中出現(xiàn)的所有代碼片段,如果在注釋中給出了TLP庫中對應(yīng)的文件路徑,則都能在TLP庫中找到源碼。除此之外的其它代碼則是為了文章需要所構(gòu)造的臨時(shí)代碼。另外,為了減少干擾,本文中所示TLP庫中的代碼均沒有加命名空間,閱讀文章和TLP庫源碼時(shí)請注意區(qū)分。


模板的基礎(chǔ)知識

返回 C++11模板元編程 - 目錄

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,818評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,185評論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,656評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,647評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,446評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,951評論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,041評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,189評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,718評論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,800評論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,419評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,420評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,755評論 2 371

推薦閱讀更多精彩內(nèi)容