學(xué)習(xí)元編程技術(shù)如何創(chuàng)建數(shù)據(jù)結(jié)構(gòu)和函數(shù),從而在編譯時(shí)進(jìn)行計(jì)算。通過(guò)《C 20模板元編程》,你將理解模板如何幫助你避免編寫(xiě)重復(fù)代碼,模板是創(chuàng)建通用庫(kù)(如標(biāo)準(zhǔn)庫(kù)或Boost)的關(guān)鍵,這些庫(kù)可以在多種程序中使用。
本書(shū)的前幾章將為你提供關(guān)于模板和元編程基礎(chǔ)的知識(shí)。然后,你將開(kāi)始練習(xí)編寫(xiě)復(fù)雜的模板,并探索高級(jí)概念,如模板遞歸、模板實(shí)參推導(dǎo)、轉(zhuǎn)發(fā)引用、類(lèi)型特征和條件編譯。在此過(guò)程中,你將學(xué)習(xí)如何編寫(xiě)變參模板,以及如何使用C 20的約束和概念為模板實(shí)參提供約束和限制。最后,你將應(yīng)用C 元編程模板的知識(shí)實(shí)現(xiàn)各種元編程模式和技術(shù)。
到本書(shū)結(jié)束時(shí),你將學(xué)會(huì)如何編寫(xiě)有效的模板,并在日常編程中使用元編程。
● 理解所有類(lèi)型模板的語(yǔ)法
● 學(xué)習(xí)特化和實(shí)例化的工作原理
● 掌握模板實(shí)參推導(dǎo)和轉(zhuǎn)發(fā)引用
● 輕松編寫(xiě)變參模板
● 掌握類(lèi)型特征和條件編譯
● 使用 C 20 的約束和概念限制模板實(shí)參
● 實(shí)現(xiàn)CRTP、混入(mixin)和標(biāo)簽派發(fā)等模式
吳詠煒、祁宇、張銀奎聯(lián)袂推薦!
通過(guò)C 20模板元編程,將編譯期計(jì)算轉(zhuǎn)化為高性能代碼引擎,讓復(fù)雜泛型設(shè)計(jì)變得簡(jiǎn)單可維護(hù)。
解決模板難讀、難寫(xiě)、難調(diào)試三大痛點(diǎn)。
玄之又玄,眾妙之門(mén)
大家都知道,AI可以寫(xiě)代碼了。你用過(guò)嗎?感覺(jué)如何?
前不久,我在準(zhǔn)備GPU訓(xùn)練營(yíng)的試驗(yàn)程序時(shí),確實(shí)用AI寫(xiě)了一些代碼,既有傳統(tǒng)的CPU端代碼,也有更現(xiàn)代的GPU端代碼。我用AI寫(xiě)代碼的目的有兩個(gè),一是提高工作效率,二是親身測(cè)試AI寫(xiě)代碼的能力。
親身測(cè)試一番之后,我有兩個(gè)比較強(qiáng)烈的感受。第一個(gè)感受是對(duì)于比較簡(jiǎn)單的任務(wù),AI確實(shí)可以寫(xiě)出質(zhì)量不錯(cuò)的代碼,不僅速度快,而且準(zhǔn)確度很高,沒(méi)有誤拼等人類(lèi)常犯的低級(jí)錯(cuò)誤。第二個(gè)感受是,隨著代碼量的上升,AI寫(xiě)的代碼也開(kāi)始具有人類(lèi)代碼常有的問(wèn)題,先是重復(fù),啰嗦,然后是有bug(錯(cuò)誤)。
眾所周知,AI領(lǐng)域吸引了大量的投資和優(yōu)秀的人才,新的成果不斷涌現(xiàn)。因此,我們比較難預(yù)測(cè)AI的代碼能力在2年后會(huì)怎么樣?在5年和10年后又會(huì)怎么樣?
AI技術(shù)的發(fā)展速度難以預(yù)測(cè),但是我覺(jué)得以下三個(gè)趨勢(shì)是比較確定的。首先,AI技術(shù)確實(shí)會(huì)改變軟件產(chǎn)業(yè)的格局,一些簡(jiǎn)單的軟件開(kāi)發(fā)任務(wù)將AI化,因?yàn)槭褂肁I技術(shù)能大大提高編碼的效率,不再需要那么多的程序員來(lái)寫(xiě)代碼。第二,隨著AI技術(shù)不斷被應(yīng)用到軟件開(kāi)發(fā)領(lǐng)域,軟件的產(chǎn)量和軟件的代碼量都將隨之上升。而且,AI產(chǎn)生的代碼也是不完美并且存在瑕疵的。軟件團(tuán)隊(duì)里將需要很多調(diào)試工程師來(lái)定位各種稀奇古怪的問(wèn)題。第三,在追求高性能、高可靠性的某些領(lǐng)域里,仍需要優(yōu)秀的人類(lèi)程序員來(lái)編寫(xiě)極端精致的代碼。就像在機(jī)器可以包餃子的今天,仍有某些餃子店使用人工包。
其實(shí),不管我的預(yù)測(cè)是否對(duì),一名好的程序員都應(yīng)該不斷錘煉自己的編碼能力,提高技術(shù)水平,讓自己寫(xiě)出的代碼越來(lái)越好。
于是,可能有人問(wèn),我已經(jīng)能寫(xiě)出很漂亮的代碼,什么樣的代碼算是更好呢?
的確,評(píng)價(jià)代碼好壞的標(biāo)準(zhǔn)有很多。在我看來(lái),第一個(gè)硬指標(biāo)就是generic,也就是通用性。展開(kāi)來(lái)說(shuō),很多代碼都有的一個(gè)通病就是長(zhǎng)相類(lèi)似的代碼有很多份,結(jié)構(gòu)類(lèi)似,但有差異,不完全相同。
我是信儒家的,但偶爾也會(huì)讀一點(diǎn)道家的作品,一般是在睡前讀,因?yàn)樽x道家的作品讀著讀著就昏昏欲睡了。為什么呢?因?yàn)榈兰业脑?huà)一般都比較虛空。用時(shí)髦的話(huà)說(shuō),就是不接地氣,難以琢磨。比如一句道可道,非常道就有很多種解釋。
我對(duì)道家的這種態(tài)度持續(xù)了很多年,直到有一天,當(dāng)我領(lǐng)悟了計(jì)算機(jī)世界的一系列經(jīng)典案例和一個(gè)永恒規(guī)律后,我又看到了玄之又玄,眾妙之門(mén)。這八個(gè)字歸納得太好了,說(shuō)出我心中所有,筆下所無(wú),改變了我對(duì)道家的態(tài)度。
什么是玄而又玄呢?傳統(tǒng)的解釋有很多種,對(duì)多數(shù)程序員來(lái)說(shuō),都不大好理解。
在我看來(lái),玄就是抽象。玄之又玄,就是抽象了再抽象。
人類(lèi)的大腦喜歡生動(dòng)具體的東西,比如小孩子都喜歡聽(tīng)故事,無(wú)論是小馬過(guò)河還是后羿射日都有具體的場(chǎng)景、人和物。長(zhǎng)大了以后喜歡刷劇也是類(lèi)似的原因。每部劇都在一個(gè)具體的時(shí)空中講一個(gè)故事。沒(méi)有哪部劇沒(méi)有人物,只有道可道,非常道。
因此,做抽象是很難的事情。也因此,很多代碼都是不夠抽象的,今天需要int類(lèi)型的max()函數(shù),那么就寫(xiě)個(gè)int類(lèi)型的;明天需要float類(lèi)型的,就把int類(lèi)型的復(fù)制一份,改成float類(lèi)型的。日積月累,整個(gè)項(xiàng)目里就有很多長(zhǎng)相類(lèi)似的代碼了。
如何提煉這樣的代碼,消除重復(fù),把它們合眾為一呢?
傳統(tǒng)C 中的模板技術(shù)就是為解決這個(gè)問(wèn)題而設(shè)計(jì)的,現(xiàn)代C 將其發(fā)揚(yáng)光大, 去除約束,增加功能,使其成為現(xiàn)代C 語(yǔ)言的一大亮點(diǎn)。
我認(rèn)識(shí)文波和榮華多年,他們都在C 語(yǔ)言和編程技術(shù)領(lǐng)域耕耘多年,孜孜不倦,滿(mǎn)懷深情。更加可貴的是,他們把熱愛(ài)轉(zhuǎn)化為實(shí)際的行動(dòng),以各種形式推動(dòng)技術(shù)的傳播和發(fā)展。他們?cè)诜g《C 模板》(第2版)之后,又將另一本模板編程的好書(shū)《C 20模板元編程》翻譯成中文,功莫大焉。
張銀奎
《軟件調(diào)試》和《軟件簡(jiǎn)史》的作者
譯 者 序
C 的演化與模板的歷史
自1979年Bjarne Stroustrup 創(chuàng)建C 以來(lái),這門(mén)語(yǔ)言經(jīng)歷了多個(gè)重要的標(biāo)準(zhǔn)化版本,每一次演進(jìn)都帶來(lái)了新的特性和改進(jìn)。從C 98的標(biāo)準(zhǔn)化到C 11迎來(lái)現(xiàn)代C 編程范式,再到C 14、C 17的穩(wěn)定和擴(kuò)展,現(xiàn)在C 20作為一個(gè)里程碑式的更新,引入了概念(Concepts)、范圍(Ranges)、協(xié)程(Coroutines)等強(qiáng)大特性。其中,C 20對(duì)模板系統(tǒng)的擴(kuò)展和改進(jìn),使得泛型編程更加直觀、高效。
C 模板的歷史可以追溯到20世紀(jì)80年代后期,它最初是為了解決代碼復(fù)用的問(wèn)題。1998年的C 標(biāo)準(zhǔn)(C 98)正式引入了模板,隨后在C 11中得到了重要增強(qiáng),如變參模板(Variadic Templates)、模板別名(Template Aliases)等。C 17進(jìn)一步引入了折疊表達(dá)式(Fold Expressions)和類(lèi)模板實(shí)參推導(dǎo)(Class Template Argument Deduction,CTAD)。到了C 20,概念(Concepts)的加入使得模板的可讀性、可維護(hù)性大幅提升。
C 模板的優(yōu)勢(shì)
C 是一門(mén)支持多種編程范式的語(yǔ)言,包括:
●過(guò)程式編程(Procedural Programming)基于函數(shù)和過(guò)程的結(jié)構(gòu)化編程。
●面向?qū)ο缶幊?OOP)通過(guò)類(lèi)、繼承和多態(tài)實(shí)現(xiàn)模塊化與復(fù)用。
●泛型編程(Generic Programming)借助模板編寫(xiě)類(lèi)型無(wú)關(guān)的代碼,提高代碼復(fù)用性和靈活性。
●函數(shù)式編程(Functional Programming)使用不可變數(shù)據(jù)和高階函數(shù),提升代碼可測(cè)試性和并發(fā)能力。
●元編程(Metaprogramming)利用編譯期計(jì)算優(yōu)化程序,提高運(yùn)行效率。
在這些范式中,模板技術(shù)是C 的核心特性,它賦予C 強(qiáng)大的泛型編程能力,使代碼適用于多種數(shù)據(jù)類(lèi)型,而不需要冗余編寫(xiě)。例如,標(biāo)準(zhǔn)模板庫(kù)(STL)的容器(如 std::vector、std::map)和算法(如 std::sort、std::find)均依賴(lài)模板實(shí)現(xiàn)。
C 模板的主要優(yōu)勢(shì)包括:
●編譯時(shí)多態(tài)(Compile-time Polymorphism)相比運(yùn)行時(shí)多態(tài)(如繼承與虛函數(shù)),模板允許編譯期進(jìn)行類(lèi)型推導(dǎo)和優(yōu)化,從而提高執(zhí)行效率。
●編譯時(shí)計(jì)算(Compile-time Computation)利用模板元編程(TMP),C 能在編譯期執(zhí)行計(jì)算,減少運(yùn)行時(shí)開(kāi)銷(xiāo)。例如,std::integral_constant 和 std::conditional 可用于選擇編譯期代碼路徑。
●代碼復(fù)用模板減少了重復(fù)代碼,提高了通用性。例如,std::enable_if 可用于 SFINAE(替換失敗非錯(cuò)誤),實(shí)現(xiàn)條件編譯。
模板的強(qiáng)大使其在現(xiàn)代C 開(kāi)發(fā)中占據(jù)重要地位,特別是在高性能計(jì)算、游戲開(kāi)發(fā)、底層系統(tǒng)編程等領(lǐng)域。掌握模板不僅能提升代碼質(zhì)量,還能幫助程序員深入理解C 語(yǔ)言的底層機(jī)制。
C 程序員的技能
對(duì)于希望深入掌握C 的開(kāi)發(fā)者而言,理解模板是進(jìn)階C 編程的必經(jīng)之路。從泛型編程(Generic Programming)、模板元編程(Template Metaprogramming),到C 20 概念(Concepts),這些技術(shù)都在現(xiàn)代C 開(kāi)發(fā)中占據(jù)了重要地位。
無(wú)論是編寫(xiě)高效的庫(kù)函數(shù),還是優(yōu)化應(yīng)用程序的性能,模板都是必不可少的工具。例如,在高性能計(jì)算(HPC)、游戲開(kāi)發(fā)、底層系統(tǒng)編程等領(lǐng)域,模板能夠提供無(wú)與倫比的靈活性和效率。掌握模板不僅能夠提高代碼質(zhì)量,還能幫助程序員更深入地理解C 語(yǔ)言的底層機(jī)制。
模板技術(shù)的學(xué)習(xí)建議
模板技術(shù)屬于編譯期編程,在學(xué)習(xí)過(guò)程中,建議結(jié)合反匯編,并善用Cpp Insights 等工具來(lái)觀察模板實(shí)例化和生成的代碼。
要系統(tǒng)學(xué)習(xí)模板技術(shù),僅靠一本書(shū)是不夠的。推薦閱讀以下書(shū)籍:
●《C Templates (第2版·中文版)》[C Templates: The Complete Guide, 2nd Edition, (美)David Vandevoorde、(德)Nicolai M. Josuttis、(美)Douglas Gregor著,何榮華、王文斌、張毅峰、楊文波譯,人民郵電出版社]經(jīng)典的C 模板書(shū)籍,全面介紹了模板技術(shù)。
●《編程原本》[Elements of ?Programming,(美)Alexnader Stepanov、(美) Paul McJones著,裘宗燕譯,人民郵電出版社]和亞歷山大的系列博文(https://www.stepanovpapers.com/)進(jìn)一步深入泛型編程。
●《C實(shí)戰(zhàn):核心技術(shù)與最佳實(shí)踐》(吳詠煒著,人民郵電出版社)現(xiàn)代C 最佳實(shí)踐。
此外,學(xué)習(xí)模板技術(shù)不能只依賴(lài)?yán)碚,還需要實(shí)踐。建議閱讀并改造以下模板庫(kù):
1. fmt(std::format的實(shí)現(xiàn))不依賴(lài)領(lǐng)域知識(shí),適合作為入門(mén)教材。
2. blaze高性能數(shù)學(xué)庫(kù)作者 Klaus Iglberger 是模板設(shè)計(jì)模式專(zhuān)家。
3. folly庫(kù)Andrei Alexandrescu 主導(dǎo),適合學(xué)習(xí)模板元編程。
4. cutlass C 模板庫(kù)Nvidia 出品,適用于深度學(xué)習(xí)優(yōu)化。
結(jié)語(yǔ)與感謝
C 模板的強(qiáng)大使得它成為現(xiàn)代C 開(kāi)發(fā)的基石,而C 20的更新更是讓模板變得更易用、更強(qiáng)大。本書(shū)的目標(biāo)是幫助讀者全面理解C 20模板的核心概念,并掌握如何在實(shí)際開(kāi)發(fā)中高效地應(yīng)用模板技術(shù)。希望本書(shū)能為你打開(kāi)C 模板編程的大門(mén),幫助你在C 領(lǐng)域更進(jìn)一步。
本書(shū)的出版離不開(kāi)各方的支持。我們衷心感謝 Bjarne Stroustrup教授,他的貢獻(xiàn)不僅塑造了C 語(yǔ)言,也為全球開(kāi)發(fā)者提供了深遠(yuǎn)的技術(shù)指導(dǎo)。
特別感謝清華大學(xué)出版社的編輯團(tuán)隊(duì),他們?cè)谛g(shù)語(yǔ)規(guī)范、技術(shù)表達(dá)及出版質(zhì)量方面提供了寶貴的支持,付出了大量的辛勤工作,確保本書(shū)得以高質(zhì)量呈現(xiàn)。我們也感謝C 社區(qū)的開(kāi)發(fā)者們,你們的深入討論與實(shí)踐經(jīng)驗(yàn)為我們提供了極大的啟發(fā)。
盡管我們力求精確,但面對(duì)C 如此龐大而復(fù)雜的體系,難免仍有不足之處。我們誠(chéng)懇歡迎讀者通過(guò)出版社反饋意見(jiàn),以便我們進(jìn)一步完善后續(xù)的修訂工作。希望本書(shū)能夠幫助廣大開(kāi)發(fā)者更深入地理解C ,更高效地運(yùn)用這門(mén)強(qiáng)大語(yǔ)言。
獻(xiàn)給那些總是渴望學(xué)習(xí)更多的好奇心靈。
Marius Bancila
貢 獻(xiàn) 者
關(guān)于作者
Marius Bancila 是一位擁有20年經(jīng)驗(yàn)的軟件工程師,在業(yè)務(wù)應(yīng)用程序開(kāi)發(fā)和其他領(lǐng)域都有豐富的解決方案經(jīng)驗(yàn)。他是Modern C Programming Cookbook和The Modern C Challenge的作者。他目前擔(dān)任軟件架構(gòu)師,專(zhuān)注于微軟技術(shù),主要使用C 和C#開(kāi)發(fā)桌面應(yīng)用程序。他熱衷于與他人分享技術(shù)專(zhuān)長(zhǎng),因此自2006年起一直被認(rèn)定為微軟C MVP,后來(lái)還獲得了開(kāi)發(fā)者技術(shù)領(lǐng)域的 MVP 稱(chēng)號(hào)。Marius 居住在羅馬尼亞,活躍于各種在線(xiàn)社區(qū)。
關(guān)于審校者
Aleksei Goriachikh擁有超過(guò)8年的C 編程經(jīng)驗(yàn)。2012年從俄羅斯的新西伯利亞國(guó)立大學(xué)獲得數(shù)學(xué)碩士學(xué)位后,Aleksei曾參與一些計(jì)算數(shù)學(xué)和優(yōu)化領(lǐng)域的研究項(xiàng)目、某CAD系統(tǒng)的幾何內(nèi)核開(kāi)發(fā),以及自動(dòng)駕駛的多線(xiàn)程庫(kù)開(kāi)發(fā)。Aleksei 最近的專(zhuān)業(yè)興趣是硅前建模。
前 言
幾十年來(lái),C 一直是世界上使用最廣泛的編程語(yǔ)言之一。它的成功不僅僅歸功于其提供的性能或者說(shuō)它的易用性(許多人對(duì)此持不同意見(jiàn)),而更可能是由于它的多功能性。C 是一種通用的多范式編程語(yǔ)言,它融合了過(guò)程式、函數(shù)式和泛型編程。
泛型編程是一種編寫(xiě)代碼的方式,例如函數(shù)和類(lèi)等實(shí)體是按照稍后實(shí)例化的類(lèi)型編寫(xiě)的。這些泛型實(shí)體僅在需要作為實(shí)參具化為特定類(lèi)型時(shí)才會(huì)實(shí)例化,這些泛型實(shí)體在C 中稱(chēng)為模板。
元編程是一種編程技術(shù),它使用模板(以及C 中的constexpr函數(shù))在編譯期生成代碼,然后將其與剩余源代碼合并以便編譯最終程序。元編程意味著其輸入或輸出中至少有一個(gè)是類(lèi)型。
正如《C 核心指南》(Bjarne Stroustrup和Herb Sutter維護(hù)的一份關(guān)于應(yīng)該做什么和不應(yīng)該做什么的文檔)中所描述的那樣,C 中的模板可謂聲名狼藉。然而,它們使得泛型庫(kù)成為可能,比如C 開(kāi)發(fā)人員一直使用的C 標(biāo)準(zhǔn)庫(kù)。無(wú)論你是自己編寫(xiě)模板,還是只使用他人編寫(xiě)的模板(比如標(biāo)準(zhǔn)容器或算法),模板都很可能是你日常編碼的一部分。
本書(shū)旨在讓讀者對(duì)C 中可用的所有范圍內(nèi)的模板都有很好的理解(從基本語(yǔ)法到C 20中的概念),這是本書(shū)前兩部分的重點(diǎn)內(nèi)容。第Ⅲ部分會(huì)幫助你將新獲得的知識(shí)付諸實(shí)踐,并使用模板進(jìn)行元編程。
本書(shū)適讀人群
本書(shū)適合想要學(xué)習(xí)模板元編程的初學(xué)者、中級(jí)C 開(kāi)發(fā)人員,以及希望快速掌握與模板相關(guān)的C 20新功能和各種慣用法和模式的高級(jí)C 開(kāi)發(fā)人員。在開(kāi)始閱讀本書(shū)之前,必須具備基本的C 編程經(jīng)驗(yàn)。
本書(shū)涵蓋內(nèi)容
第1章模板簡(jiǎn)介。通過(guò)幾個(gè)簡(jiǎn)單的例子介紹了C 中模板元編程的概念,討論了為什么我們需要模板以及模板的優(yōu)缺點(diǎn)。
第2章模板基礎(chǔ)。探討了C 中所有形式的模板:函數(shù)模板、類(lèi)模板、變量模板和別名模板。我們討論了其中每一個(gè)的語(yǔ)法和它們?nèi)绾喂ぷ鞯募?xì)節(jié)。此外,還討論了模板實(shí)例化和特化的關(guān)鍵概念。
第3章變參模板。專(zhuān)門(mén)介紹了變參模板,即具有可變數(shù)量模板形參的模板。我們?cè)敿?xì)討論了變參函數(shù)模板、變參類(lèi)模板、變參別名模板和變參變量模板、形參包及其展開(kāi)方式,以及幫助我們簡(jiǎn)化編寫(xiě)變參模板的折疊表達(dá)式。
第4章高級(jí)模板概念。對(duì)一系列高級(jí)模板概念進(jìn)行了分組,比如依賴(lài)名稱(chēng)和名稱(chēng)查找、模板實(shí)參推導(dǎo)、模板遞歸、完美轉(zhuǎn)發(fā)、泛型和模板lambda函數(shù)。通過(guò)了解這些主題,讀者將能夠極大地?cái)U(kuò)展他們可以閱讀或編寫(xiě)的模板的種類(lèi)。
第5章類(lèi)型特征和條件編譯。專(zhuān)門(mén)討論類(lèi)型特征。讀者將了解類(lèi)型特征、標(biāo)準(zhǔn)庫(kù)提供的特征以及如何使用它們解決不同的問(wèn)題。
第6章概念和約束。介紹了新的C 20機(jī)制,通過(guò)概念和約束定義模板實(shí)參的需求。你將了解指定約束的各種方法。此外,還概述了C 20標(biāo)準(zhǔn)概念庫(kù)的內(nèi)容。
第7章模式和慣用法。探討了一系列獨(dú)立的高級(jí)主題,即利用迄今為止學(xué)到的知識(shí)實(shí)現(xiàn)各種模式。我們探討了靜態(tài)多態(tài)、類(lèi)型擦除、標(biāo)簽派發(fā)和模式的概念,比如奇異遞歸模板模式、表達(dá)式模板、混入和類(lèi)型列表。
第8章范圍和算法。專(zhuān)注于理解容器、迭代器和算法,它們是標(biāo)準(zhǔn)模板庫(kù)的核心組件。你將在這里學(xué)習(xí)如何為其編寫(xiě)泛型容器和迭代器類(lèi)型以及通用算法。
第9章范圍庫(kù)。探討了新的C 20范圍庫(kù)及其關(guān)鍵特性,例如范圍、范圍適配器和約束算法。這些使我們能夠編寫(xiě)更簡(jiǎn)單的代碼來(lái)處理范圍。此外,你還將在這里學(xué)習(xí)如何編寫(xiě)自己的范圍適配器。
附錄是一個(gè)簡(jiǎn)短的結(jié)語(yǔ),提供了本書(shū)的總結(jié)。
問(wèn)題答案包含了所有章節(jié)中習(xí)題的答案。
充分利用本書(shū)
要開(kāi)始閱讀本書(shū),首先需要對(duì)C 編程語(yǔ)言有一些基本的了解。需要了解有關(guān)類(lèi)、函數(shù)、運(yùn)算符、函數(shù)重載、繼承、虛函數(shù)等的語(yǔ)法和基礎(chǔ)知識(shí)。不過(guò),對(duì)模板知識(shí)不做要求,因?yàn)楸緯?shū)將從頭開(kāi)始教你一切。
本書(shū)中的所有代碼示例都是跨平臺(tái)的。這意味著你可以使用任何編譯器來(lái)構(gòu)建和運(yùn)行它們。然而,盡管許多代碼段適用于C 11編譯器,但也有一些代碼段需要兼容C 17或C 20的編譯器。因此,建議你使用支持C 20的編譯器版本,以便運(yùn)行所有示例。書(shū)中的示例已使用MSVC 19.30 (Visual Studio 2022)、GCC 12.1/13和Clang 13/14進(jìn)行了測(cè)試。如果你的機(jī)器上沒(méi)有這樣一個(gè)兼容C 20的編譯器,可以試著網(wǎng)上下載一個(gè)。我們推薦以下幾個(gè)方案:
●Compiler Explorer (https://godbolt.org/)
●Wandbox (https://wandbox.org/)
●C Insights (https://cppinsights.io/)
本書(shū)多次引用C Insights在線(xiàn)工具來(lái)分析編譯器生成的代碼。
如果你想檢查編譯器對(duì)不同版本的C 標(biāo)準(zhǔn)的支持,應(yīng)該參考頁(yè)面https://en.cppreference.com/w/cpp/compiler_support。
提及標(biāo)準(zhǔn)和延伸閱讀
在本書(shū)中,我們會(huì)多次提到C 標(biāo)準(zhǔn)。此文件版權(quán)歸國(guó)際標(biāo)準(zhǔn)化組織所有。官方的C 標(biāo)準(zhǔn)文檔可以從這里購(gòu)買(mǎi):https://www.iso.org/standard/79358.html。但是,C 標(biāo)準(zhǔn)的多個(gè)草案以及相應(yīng)源碼可以在GitHub上免費(fèi)獲得,網(wǎng)址為https://github.com/ cplusplus/draft。可以在https://isocpp.org/ std/the-standard鏈接上找到有關(guān)C 標(biāo)準(zhǔn)的更多信息。
C Reference網(wǎng)站是C 開(kāi)發(fā)人員的一個(gè)很好的在線(xiàn)資源,網(wǎng)址為https://en. cppreference.com/。它提供了直接派生自C 標(biāo)準(zhǔn)的C 語(yǔ)言的詳盡文檔。本書(shū)多次引用了C 參考中的內(nèi)容。C 參考的內(nèi)容是基于CC-BY-SA協(xié)議的,https://en.cppreference. com/w/Cppreference:Copyright/CC-BY-SA。
(在每一章的末尾,你會(huì)發(fā)現(xiàn)一個(gè)名為延伸閱讀的部分,該部分包含一份用作參考書(shū)目的閱讀材料清單,推薦閱讀以加深對(duì)所介紹主題的理解。)
下載示例代碼文件
可以從GitHub上下載本書(shū)的示例代碼文件,網(wǎng)址為https://github.com/ PacktPublishing/Template-Metaprogramming-with-CPP。也可以?huà)呙璺獾锥S碼下載。如果代碼有更新,將會(huì)在GitHub倉(cāng)庫(kù)中更新它。
下載彩圖
我們還提供了一個(gè)PDF文件,其中包含本書(shū)中使用的屏幕截圖和圖表的彩圖?梢栽诖颂幭螺d:https://packt.link/Un8j5。也可以?huà)呙璺獾锥S碼下載。
使用的約定
本書(shū)使用了一些文本約定。
文本中的代碼:表示文本中的代碼詞匯、數(shù)據(jù)庫(kù)表名、文件夾名、文件名、文件擴(kuò)展名、路徑名、虛擬URL、用戶(hù)輸入和Twitter用戶(hù)名/賬號(hào)標(biāo)識(shí)。這里有一個(gè)例子:這個(gè)問(wèn)題可以通過(guò)將init設(shè)置為依賴(lài)名稱(chēng)來(lái)解決。
代碼塊的格式如下:
template
structparser:base_parser
{
voidparse()
{
this->init(); // 正確
std::cout<<"parse\n";
}
};
按如下方式編寫(xiě)任意命令行的輸入或輸出:
fatal error:recursive template instantiation exceeded maximum depth of 1024
use -ftemplate-depth=N to increase recursive template instantiation depth
粗體:表示一個(gè)新術(shù)語(yǔ)、一個(gè)重要單詞或你在屏幕上看到的單詞。例如,菜單或?qū)υ?huà)框中的單詞以粗體顯示。這里有一個(gè)例子:容量為8,大小為0,頭部和尾部都指向索引0。
提示或重要說(shuō)明
迭代器概念在第6章概念與約束中進(jìn)行了簡(jiǎn)要討論。
本書(shū)的參考文獻(xiàn)和問(wèn)題答案可掃描封底二維碼下載。
馬里烏斯·班西拉(Marius Bancila)于2002年作為一名軟件開(kāi)發(fā)人員開(kāi)始了職業(yè)生涯,專(zhuān)注于使用 Visual C 、C# 和 .NET 框架開(kāi)發(fā)桌面應(yīng)用程序。盡管多年來(lái)使用過(guò)許多編程和腳本語(yǔ)言(例如 Pascal、C、C 、Java、JavaScript、C#、VB.NET、MC 、C /CLI、HTML、CSS 等),但 C 始終是他的首選語(yǔ)言。目前他在挪威的Visma公司擔(dān)任 ERP 系統(tǒng)的系統(tǒng)架構(gòu)師。
Marius Bancila是Modern C Programming Cookbook和Modern C Challenge等多本C 技術(shù)圖書(shū)的作者,熱衷于與他人分享技術(shù)專(zhuān)長(zhǎng),并因此自2006年起連續(xù)18年被授予微軟MVP(最有價(jià)值專(zhuān)家)稱(chēng)號(hào)。他撰寫(xiě)了大量技術(shù)文章,創(chuàng)建和參與了多個(gè)開(kāi)源項(xiàng)目,并活躍于各類(lèi)在線(xiàn)開(kāi)發(fā)者社區(qū)。
第Ⅰ部分 模板的核心概念
第1章 模板的簡(jiǎn)介 3
1.1 理解模板的必要性 3
1.2 編寫(xiě)你的第一個(gè)模板 6
1.3 理解模板術(shù)語(yǔ) 9
1.4 模板的簡(jiǎn)史 10
1.5 模板的優(yōu)缺點(diǎn) 12
1.6 總結(jié) 12
1.7 問(wèn)題 13
第2章 模板的基礎(chǔ) 15
2.1 定義函數(shù)模板 15
2.2 定義類(lèi)模板 18
2.3 定義成員函數(shù)模板 20
2.4 理解模板形參 21
2.4.1 類(lèi)型模板形參 22
2.4.2 非類(lèi)型模板形參 23
2.4.3 模板模板形參 28
2.4.4 默認(rèn)模板實(shí)參 30
2.5 理解模板實(shí)例化 32
2.5.1 隱式實(shí)例化 32
2.5.2 顯式實(shí)例化 35
2.6 理解模板特化 39
2.6.1 顯式特化 39
2.6.2 部分特化 43
2.7 定義變量模板 46
2.8 定義別名模板 49
2.9 探索泛型lambda和lambda模板 51
2.10 總結(jié) 57
2.11 問(wèn)題 57
第3章 變參模板 59
3.1 理解變參模板的必要性 59
3.2 變參函數(shù)模板 61
3.3 形參包 65
3.4 變參類(lèi)模板 73
3.5 折疊表達(dá)式 79
3.6 變參別名模板 82
3.7 變參變量模板 84
3.8 總結(jié) 84
3.9 問(wèn)題 85
第Ⅱ部分 高級(jí)模板特性
第4章 高級(jí)模板的概念 89
4. 1 理解名稱(chēng)綁定和依賴(lài)名稱(chēng) 89
4.1.1 兩階段名稱(chēng)查找 91
4.1.2 依賴(lài)類(lèi)型名稱(chēng) 94
4.1.3 依賴(lài)模板名稱(chēng) 96
4.1.4 當(dāng)前實(shí)例化 97
4.2 探索模板遞歸 99
4.3 函數(shù)模板實(shí)參推導(dǎo) 103
4.4 類(lèi)模板實(shí)參推導(dǎo) 112
4.5 轉(zhuǎn)發(fā)引用 117
4.6 decltype說(shuō)明符 123
4.7 std::declval類(lèi)型運(yùn)算符 128
4.8 理解模板中的友元關(guān)系 130
4.9 總結(jié) 135
4.10 問(wèn)題 135
第5章 類(lèi)型特征和條件編譯 137
5.1 理解和定義類(lèi)型特征 137
5.2 探索SFINAE及其目的 141
5.3 使用enable_if類(lèi)型特征啟用SFINAE 145
5.4 使用 constexpr if 149
5.5 探索標(biāo)準(zhǔn)庫(kù)類(lèi)型特征 152
5.5.1 查詢(xún)類(lèi)型類(lèi)別 152
5.5.2 查詢(xún)類(lèi)型屬性 155
5.5.3 查詢(xún)支持的操作 157
5.5.4 查詢(xún)類(lèi)型之間的關(guān)系 158
5.5.5 修改const/volatile說(shuō)明符、引用、指針或符號(hào) 159
5.5.6 各種轉(zhuǎn)換 160
5.6 使用類(lèi)型特征的實(shí)際例子 163
5.6.1 實(shí)現(xiàn)拷貝算法 163
5.6.2 構(gòu)建同質(zhì)的變參函數(shù)模板 166
5.7 總結(jié) 167
5.8 問(wèn)題 168
第6章 概念和約束 169
6.1 理解概念的必要性 169
6.2 定義概念 174
6.3 探索requires表達(dá)式 176
6.3.1 簡(jiǎn)單要求 177
6.3.2 類(lèi)型要求 179
6.3.3 復(fù)合要求 180
6.3.4 嵌套要求 182
6.4 組合約束 183
6.5 了解帶約束模板的順序 187
6.6 約束非模板成員函數(shù) 190
6.7 約束類(lèi)模板 193
6.8 約束變量模板和模板別名 194
6.9 學(xué)習(xí)更多指定約束的方法 195
6.10 使用概念約束auto形參 196
6.11 探索標(biāo)準(zhǔn)概念庫(kù) 198
6.12 總結(jié) 202
6.13 問(wèn)題 202
第Ⅲ部分 模板的應(yīng)用
第7章 模式和慣用法 205
7.1 動(dòng)態(tài)多態(tài)和靜態(tài)多態(tài) 205
7.2 奇異遞歸模板模式 208
7.2.1 使用CRTP限制對(duì)象實(shí)例化的次數(shù) 210
7.2.2 使用CRTP添加功能 211
7.2.3 實(shí)現(xiàn)組合設(shè)計(jì)模式 213
7.2.4 標(biāo)準(zhǔn)庫(kù)中的CRTP 217
7.3 混入 220
7.4 類(lèi)型擦除 225
7.5 標(biāo)簽派發(fā) 231
7.6 表達(dá)式模板 236
7.7 類(lèi)型列表 243
7.7.1 使用類(lèi)型列表 245
7.7.2 實(shí)現(xiàn)對(duì)類(lèi)型列表的操作 247
7.8 總結(jié) 253
7.9 問(wèn)題 254
第8章 范圍和算法 255
8.1 理解容器、迭代器和算法的設(shè)計(jì) 255
8.2 創(chuàng)建自定義容器和迭代器 262
8.2.1 實(shí)現(xiàn)環(huán)形區(qū)緩沖容器 263
8.2.2 為環(huán)形緩沖區(qū)容器實(shí)現(xiàn)迭代器類(lèi)型 269
8.3 編寫(xiě)自定義通用算法 275
8.4 總結(jié) 277
8.5 問(wèn)題 278
第9章 范圍庫(kù) 279
9.1 從抽象范圍到范圍庫(kù) 279
9.2 理解范圍概念和視圖 281
9.3 理解受約束算法 291
9.4 編寫(xiě)自己的范圍適配器 294
9.5 總結(jié) 300
9.6 問(wèn)題 300
附錄A 結(jié)束語(yǔ) 301
以下內(nèi)容可掃描封底二維碼下載
問(wèn)題答案 303
參考文獻(xiàn) 313