熟悉C++的程序員都知道践美,C++是一門多范式編程語言,支持面向過程找岖、面向對象陨倡、泛型編程以及函數(shù)式編程范式。然而提到C++模板元編程许布,在很多人心里這卻是C++里的黑魔法:它很難學習兴革,一旦進入這個領域曾經那些熟悉的東西(if,for...)都不再靈驗爹脾;它很強大帖旨,但現(xiàn)實中卻鮮見有人用它來解決實際問題,除過偶爾在一些編碼練習中被某些C++狂熱粉當做奇淫巧技拿出來秀秀肌肉灵妨。
其實模板元編程是C++所支持的一種非常強大的計算能力解阅,它是使用C++開發(fā)高質量庫和框架所離不開的一項武器。
掌握C++模板元編程泌霍,至少可以在以下場合幫助到你:
- 實現(xiàn)高擴展性货抄,并且兼具高性能的庫
- 實現(xiàn)靈活且易于使用的框架
- 實現(xiàn)基于C++的內部DSL(Domain Specific Language)
- 幫助更深入地理解并使用模板和泛型編程,更好地去使用C++ STL庫中的高級特性
如果你是一個C++的庫或框架的開發(fā)者朱转,了解和掌握一些模板元編程的知識蟹地,可以讓你的作品更易于擴展、擁有更易用的接口藤为,甚至更高的運行時效率怪与。而即使你只使用C++設計和開發(fā)應用程序,了解模板元編程也會幫助你更好的去使用STL庫的各種特性缅疟,幫助你的局部設計做的更加漂亮分别。
實際上C++模板元編程技術已經滲透在我們日常使用的各種庫和框架中遍愿,例如我們最常使用的STL庫以及各種xUnit測試框架和mock框架≡耪叮可以說沼填,模板元編程是中級C++程序員邁向高級的必經之路!
然而現(xiàn)實是括授,C++模板元編程的學習之旅卻并不平坦坞笙。
一方面,由于C++模板元編程的本質是函數(shù)式編程荚虚,熟練掌握并使用函數(shù)式編程的程序員比較小眾薛夜,絕大多數(shù)程序員初次進入這個領域時面對模式匹配、遞歸和不可變性時都會手足無措曲管。另一方面却邓,由于C++的模板元編程能力是被意外發(fā)現(xiàn)的,不像別的函數(shù)式編程語言經過良好的設計院水,所以C++的這種函數(shù)式計算能力天生存在著各種缺陷腊徙,直到C++11標準才開始逐漸完善起來。在之前很多重要特性都靠很繞的方式去迂回實現(xiàn)檬某,增加了學習的難度撬腾。
另外,市面上介紹模板元編程的書和資料也乏善可陳恢恼,以下的書相對還不錯民傻,但對于模板元編程的介紹仍舊存在一些問題:
《C++ Templates Complete》
介紹C++模板知識最全面的一本書,涉及到了模板各個方面的基礎知識和應用技巧场斑。由于元編程并不是此書重點漓踢,所以僅有短短一章列舉了一些利用模板元編程做數(shù)值計算的例子。現(xiàn)實中使用模板元編程單純做數(shù)值計算的場合并不多漏隐,模板元編程更大的價值在于做類型計算和代碼生成喧半,書中卻涉及甚少。《Modern C++ Design》
介紹如何使用模板進行C++高階設計的一本書青责。介紹了TypeLists
的概念挺据,作為一種重要的編譯時數(shù)據(jù)結構,是元編程的基礎脖隶。但遺憾作者并沒有明確的提出元編程的概念扁耐,也沒有對C++編譯時的運算特征進行總結和提煉。最后由于此書基于的C++ 98標準對于模板以及編譯期類型計算支持上的欠缺产阱,書中介紹的不少實現(xiàn)比較迂回復雜婉称。《C++模板元編程》
正式介紹C++模板元編程的一本書,引入了元函數(shù)的概念。通過對模板計算的規(guī)范化王暗,發(fā)揮了編譯期元函數(shù)可組合的優(yōu)勢榨乎。遺憾的是,此書只能算是boost中mpl庫的用戶手冊瘫筐,基本上是在講mpl庫的用戶接口和使用方法,沒有涉及庫的實現(xiàn)細節(jié)☆硪Γ現(xiàn)實中我們采用元編程解決問題策肝,一般不會引用boost這么重的庫,往往只會在某一局部借鑒類似的設計技巧隐绵。所以對于元編程來說之众,授之以漁的意義遠大于授之以魚。另外由于boost mpl庫中用了大量C++預處理期代碼生成技術依许,導致通過閱讀mpl源碼去掌握模板元編程的同學一上來就陷入到一堆宏中棺禾,對于學習元編程增加了非常多的干擾因素。
基于以上原因峭跳,我基于C++11標準實現(xiàn)了一個模板元編程的基礎庫:TLP (https://github.com/MagicBowen/tlp)膘婶,然后再通過本手冊來為大家全面介紹C++模板元編程的基本知識和使用技巧。
TLP庫包含以下內容:
- 基本的編譯期數(shù)據(jù)類型和算法蛀醉;
- 基本的編譯期數(shù)據(jù)結構
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ù)轉發(fā)”等规求;
- 一個面向模板元編程的測試框架筐付,用它描述的所有測試用例執(zhí)行在C++的編譯期,我們使用它來對TLP進行測試阻肿;
除此之外瓦戚,TLP庫中還包含了如下示例代碼,用來演示如何在現(xiàn)實場景中應用好模板元編程和TLP庫:
- 示范了如何使用模板元編程做純編譯期計算丛塌,完成一個自動數(shù)三角形的程序较解;
- 示范了如何使用模板元編程技術來實現(xiàn)代碼生成,自動創(chuàng)建visitor設計模式赴邻;
- 示范了如何使用模板元編程技術來實現(xiàn)一個DSL印衔,用于描述并生成有限狀態(tài)機;
上面提到的TypeList
以及使用代碼生成來創(chuàng)建visitor設計模式
的原創(chuàng)者是《Modern C++ Design》的作者Andrei Alexandrescu姥敛。在TLP中我用C++11對TypeList
及其算法進行了改寫奸焙,并進行了高階函數(shù)的擴展。得益于C++11標準對模板元編程的更好支持彤敛,新的實現(xiàn)比起原來的更加清晰和簡潔与帆。
示例代碼中利用模板元編程創(chuàng)建有限狀態(tài)機DSL
的設計最初來自于《C++模板元編程》一書,為了讓其更好被理解墨榄,我對例子以及代碼進行了較大的改編鲤桥。
除了上面的例子,本手冊中還介紹了我自己開發(fā)的針對C++模塊和子系統(tǒng)FT(Functional Test)級別的測試框架dates渠概,展示了它如何使用模板元編程來進行類型萃取茶凳、類型選擇以及類型校驗,最終使得框架變得更易用播揪、更高效以及更安全贮喧。這些技巧可以幫助到大家更好地使用模板元編程去解決現(xiàn)實問題。
最后猪狈,TLP庫自身的測試通過一個原創(chuàng)的C++模板元編程測試框架箱沦。該框架專門針對C++編譯期計算進行測試,它的用法和常見的xUnit測試框架類似雇庙,但有趣的是使用該框架描述的所有測試用例的執(zhí)行發(fā)生在C++編譯期谓形。本文會專門介紹該框架的一些實現(xiàn)細節(jié)。
C++模板元編程當年被提出來的時候疆前,函數(shù)式編程還沒有像今天這樣被更多的人所了解和接受寒跳,當時的C++標準和編譯器對模板和編譯期計算的支持也存在著很多缺陷。然而到了今天竹椒,很多事情發(fā)生了變化童太!本文的讀者最好能夠有一些函數(shù)式編程的基礎,了解C++模板的基本用法,熟悉一些C++11標準的內容书释。當然文中所有用的到模板技術翘贮、C++11標準和涉及到的函數(shù)式編程概念也都會專門介紹和說明。
如果你從來沒有接觸過C++模板元編程爆惧,那么最好從一開始就把它當做一門全新的語言去學習狸页,從頭掌握C++中這種不一樣的計算模型和語法。這種新的語言和我們熟識的運行期C++在語法和計算模型上都有較大的差異扯再,但它的優(yōu)勢在于能和運行期C++緊密無縫地結合在一起肴捉,無論是在提高程序可擴展性還是提高程序運行效率上,都能創(chuàng)造出非常不可思議的效果來叔收。希望通過本手冊,可以讓更多的人掌握C++模板元編程這一設計利器傲隶,在適合的場合下以更有效饺律、更酷的方式去解決問題。
文中出現(xiàn)的所有代碼片段跺株,如果在注釋中給出了TLP庫中對應的文件路徑复濒,則都能在TLP庫中找到源碼。除此之外的其它代碼則是為了文章需要所構造的臨時代碼乒省。另外巧颈,為了減少干擾,本文中所示TLP庫中的代碼均沒有加命名空間袖扛,閱讀文章和TLP庫源碼時請注意區(qū)分砸泛。