版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、C+模板元編程技術(shù)與應(yīng)用榮耀動(dòng)機(jī)讓更多的C+程序員了解模板元編程,并在此過程中獲得快樂!目錄* 歷史* 導(dǎo)入范例* 主要思想* 靜態(tài)語言設(shè)施* 控制結(jié)構(gòu)* 數(shù)據(jù)結(jié)構(gòu)* 數(shù)值計(jì)算* 類型計(jì)算* 代碼生成* 斷言和契約* 庫* DSEL設(shè)計(jì)* 結(jié)語* 資源歷史1994年,在圣迭哥舉行的一次C+標(biāo)準(zhǔn)委員會(huì)會(huì)議期間,Erwin Unruh展示了一段特別的代碼,可以在編譯期以編譯錯(cuò)誤信息的方式產(chǎn)生從2到某個(gè)給定值之間的所有質(zhì)數(shù)。這份代碼的原始版本見注5,修訂版見注6。可以使用GCC編譯器觀察到上述效果。同年夏天,Todd Veldhuizen受Erwin的例子啟發(fā),發(fā)現(xiàn)可以使用C+模板進(jìn)行元編程(met
2、aprogramming),并發(fā)表了一份技術(shù)報(bào)告。次年5月又在C+ Report上發(fā)表了一篇名為“Using C+ template metaprograms”的文章,從而將Erwin Unruh發(fā)現(xiàn)的C+編譯期模板編程(Compile-time Template Programming)進(jìn)一步精化為C+模板元編程(Template Metaprogramming,TMP)。導(dǎo)入范例/ 主模板templatestruct Fib enum Result = Fib:Result + Fib:Result ;/ 完全特化版template struct Fib enum Result = 1 ;
3、/ 完全特化版template struct Fib enum Result = 0 ;1.計(jì)算Fibonacci數(shù)列第N項(xiàng)/ 示例int main() int i = Fib:Result; / std:cout i std:endl; 主模板用于處理一般的邏輯處理N=1的情況處理N=0的情況特化必須放在主模板之后導(dǎo)入范例語句int i = Fib:Result;被VC7.1編譯成如下指令(Intel P4 CPU): 00411A1E mov dword ptr i,37h 字面量37h即為Fibonacci數(shù)列的第10項(xiàng)的值。可見,F(xiàn)ib:Result的確被評(píng)估于編譯期,結(jié)果作為處理器指
4、令的一部分而被存儲(chǔ)起來。運(yùn)作機(jī)理:當(dāng)編譯器實(shí)例化Fib時(shí),為了給其enum Result賦值,編譯器需要對(duì)Fib和Fib進(jìn)行實(shí)例化,同理,又需要針對(duì)Fib和Fib實(shí)例化同樣的模板,當(dāng)實(shí)例化到Fib和Fib的時(shí)候,完全特化版被實(shí)例化,至此遞歸結(jié)束。這個(gè)處理過程類似于遞歸函數(shù)調(diào)用,編譯器被用于解釋元程序,生成的結(jié)果程序中僅包含一個(gè)常量值。導(dǎo)入范例/ 主模板templatestruct IfThenElse typedef T1 ResultType;/ 局部特化templatestruct IfThenElse typedef T2 ResultType;/ 示例IfThenElse:Result
5、Type i; / i的類型為int2.類型選擇基于給定的布爾常量表達(dá)式在兩個(gè)類型之中二選一。若表達(dá)式為true,則T1被typedef為ResultT,否則ResultT代表T2。只針對(duì)模板參數(shù)的局部進(jìn)行特化。主要思想利用模板特化機(jī)制實(shí)現(xiàn)編譯期條件選擇結(jié)構(gòu),利用遞歸模板實(shí)現(xiàn)編譯期循環(huán)結(jié)構(gòu),模板元程序則由編譯器在編譯期解釋執(zhí)行。靜態(tài)語言設(shè)施模板元編程使用靜態(tài)C+語言成分,編程風(fēng)格類似于函數(shù)式編程,其中不可以使用變量、賦值語句和迭代結(jié)構(gòu)等。在模板元編程中,主要操作整型(包括布爾類型、字符類型、整數(shù)類型)常量和類型。被操縱的實(shí)體也稱為元數(shù)據(jù)(Metadata)。所有元數(shù)據(jù)均可作為模板參數(shù)。其他元數(shù)
6、據(jù)類型還包括枚舉、函數(shù)指針/引用、全局對(duì)象的指針/引用以及指向成員的指針等。另外,已經(jīng)有一些編譯期浮點(diǎn)數(shù)計(jì)算探索(參見注7)。由于在模板元編程中不可以使用變量,我們只能使用typedef名字和整型常量。它們分別采用一個(gè)類型和整數(shù)值進(jìn)行初始化,之后不能再賦予新的類型或數(shù)值。如果需要新的類型或數(shù)值,必須引入新的typedef名字或常量。靜態(tài)語言設(shè)施編譯期賦值通過整型常量初始化和typedef語句實(shí)現(xiàn)。例如:enum Result = Fib:Result + Fib:Result;或static const int Result = Fib:Result + Fib:Result;成員類型則通過t
7、ypedef引入,例如:typedef T1 Result;新、舊編譯器均支持靜態(tài)語言設(shè)施條件結(jié)構(gòu)采用模板特化或條件操作符實(shí)現(xiàn)。如果需要從兩個(gè)或更多種類型中選其一,可以使用模板特化 ,如前述的IfThenElse??梢允褂脳l件操作符返回兩個(gè)候選數(shù)值之一,例如:templatestruct Max enum Result = (a b) ? a : b ; ;靜態(tài)C+代碼使用遞歸而不是循環(huán)語句。遞歸的終結(jié)采用模板特化實(shí)現(xiàn)。如果沒有充當(dāng)終結(jié)條件的特化版,編譯器將一直實(shí)例化下去,一直到達(dá)編譯器的極限。C+標(biāo)準(zhǔn)建議編譯器實(shí)現(xiàn)至少要支持17層實(shí)例化。大多數(shù)編譯器支持的遞歸實(shí)例化數(shù)目遠(yuǎn)不止17。例如,GC
8、C支持多達(dá)500層遞歸模板實(shí)例化。C+靜態(tài)語言設(shè)施是圖靈完備的,理論上可以用于實(shí)現(xiàn)任何可實(shí)現(xiàn)的算法。可以使用模板元編程實(shí)現(xiàn)與運(yùn)行期C+所對(duì)應(yīng)的程序流程控制結(jié)構(gòu)??刂平Y(jié)構(gòu)/ If/ 主模板templatestruct If;/ 完全特化版templatestruct If static void F() / 待執(zhí)行的語句 ;/ 完全特化版templatestruct If static void F() / 待執(zhí)行的語句 ;/ 示例If:F();主模板未必一定要予以定義。此主模板純粹供隨后的特化所用??刂平Y(jié)構(gòu)/ For/ 主模板templatestruct For static inline v
9、oid f() / 待執(zhí)行的語句 For:f(); ;/ 完全特化版templatestruct For static inline void f() / 空,什么都不做 ;類似地,可以給出While、Do-While實(shí)現(xiàn)/ 使用For:f();我們必須給出這個(gè)什么也不做的f(),否則會(huì)導(dǎo)致N=1時(shí)實(shí)例化失敗。控制結(jié)構(gòu)/ Switch/ 主模板templatestruct Switch static void f() / 缺省情況下執(zhí)行的語句 ;/ 完全特化版1templatestruct Switch static void f() / 待執(zhí)行的語句1 ;/ 完全特化版2templatest
10、ruct Switch static void f() / 待執(zhí)行的語句2 ;/ 示例Switch:f();該實(shí)現(xiàn)不夠直觀,在語法上和運(yùn)行期switch相去甚遠(yuǎn)。一個(gè)更自然的實(shí)現(xiàn)應(yīng)該支持類似于運(yùn)行期switch的語法控制結(jié)構(gòu)struct A static void execute() cout A endl; ;struct B static void execute() cout B endl; ;struct C static void execute() cout Default endl; ;/ 用法示例Switch(1+1-2), Case1, A, Case2, B, Case :
11、Result:execute(); / 打印“Default我們希望支持這樣的用法控制結(jié)構(gòu)/ Switchconst int DEFAULT = -1; struct NilCase;template struct Case enum tag = tag_; typedef Type_ Type; typedef Next_ Next;/ 主模板template struct Switchprivate: typedef typename Case:Next NextCase; enum caseTag = Case:tag, found = (caseTag = tag | caseTag
12、= DEFAULT);public: typedef typename IfThenElsefound, typename Case:Type, typename Switch:Result:ResultType Result;/ 局部特化template struct Switch typedef NilCase Result;利用typename消除歧義 如前述 類似地,可以分別給出更符合直覺的、結(jié)構(gòu)性更好的For、While、Do-While實(shí)現(xiàn)??刂平Y(jié)構(gòu)最早提出編譯期控制思想并給出雛形實(shí)現(xiàn)的是Todd Veldhuizen,參見注1。Krysztof Czarnecki, Ulrich
13、 Eisenecker則實(shí)現(xiàn)了更一般化的編譯期結(jié)構(gòu)(如剛才展示的第二個(gè)版本的Switch)參見注12??梢允褂们短啄0鍖?shí)現(xiàn)復(fù)雜的編譯期數(shù)據(jù)結(jié)構(gòu)(編譯期容器),其中可以容納整數(shù)和類型??疾靸蓚€(gè)例子:一個(gè)序列,為Loki庫中的Typelist;一個(gè)是二叉樹(或樹的二叉樹表示)結(jié)構(gòu)。數(shù)據(jù)結(jié)構(gòu)Boost MPL庫中定義有vector、deque、list、set以及map等序列,它們都是編譯期數(shù)據(jù)結(jié)構(gòu)。數(shù)據(jù)結(jié)構(gòu)/ Typelisttemplate struct Typelist typedef T Head; typedef U Tail; / 計(jì)算長度/ 主模板template struct Len
14、gth;/ 局部特化template struct LengthTypelist enum value = 1 + Length:value ; / 完全特化template struct Length enum value = 0 ;/ 示例typedef Typelistchar, Typelist T;cout Length:value endl; / 2/ 哨衛(wèi)類型class NullType ;一個(gè)typelist的 長 度 等 于tail的長度加1數(shù)據(jù)結(jié)構(gòu)/ BTreeconst int LEAFVALUE = -1; / 葉子節(jié)點(diǎn)值/ 葉子節(jié)點(diǎn)struct BTLeaf enum
15、 Value = LEAFVALUE ; typedef BTLeaf Left; typedef BTLeaf Right;template struct BTree / BTNode enum Value = N ; typedef Left_ Left; typedef Right_ Right;數(shù)據(jù)結(jié)構(gòu)/ 判樹是否為空/ 主模板template struct IsEmpty;/ 局部特化template struct IsEmptyBTree enum Result = false ;/ 完全特化templatestruct IsEmptyBTree enum Result = tru
16、e ;數(shù)據(jù)結(jié)構(gòu)/ 示例typedef BTree tree1;typedef BTree tree2;typedef BTree1, BTree, BTree tree3;int main() cout IsEmpty:Result endl; / 1 cout IsEmpty:Result endl; / 0 cout IsEmpty:Result endl; / 0等價(jià)于:typedef BTree aTree2;由于模板元編程最先是因?yàn)閿?shù)值計(jì)算而被發(fā)現(xiàn)的,因此早期的研究工作主要集中于數(shù)值計(jì)算方面,先鋒是Todd Veldhuizen和Blitz+庫。元編程在該領(lǐng)域最早的應(yīng)用是實(shí)現(xiàn)“循環(huán)開
17、解(Unroll Loop)”。其他庫(例如MTL、POOMA等)也采用了這種技術(shù)。數(shù)值計(jì)算數(shù)值計(jì)算領(lǐng)域還有很多重要的模板元編程(相關(guān))技術(shù),例如“表達(dá)式模板(Expression Templates)”(見注2)、“部分求值( Partial Evaluation)”(見注3)等。數(shù)值計(jì)算/ 主模板template struct DotProduct static T Result(T* a, T* b) return *a * *b + DotProduct:Result(a+1, b+1); ;/ 局部特化template struct DotProduct static T Resul
18、t(T* a, T* b) return *a * *b; ;一個(gè)經(jīng)典的循環(huán)開解例子:計(jì)算向量點(diǎn)積算法思想:向量a和b的點(diǎn)積=向量a和b首元素的乘積+剩余維度向量之點(diǎn)積一維向量的情形數(shù)值計(jì)算/ 示例int main() int a5 = 1, 2, 3, 4, 5 ; int b5 = 6, 7, 8, 9, 10; cout DotProduct:Result(a, b) endl; / 130/ 循環(huán)開解過程DotProduct:result(a,b)= *a * *b + DotProduct:result(a+1,b+1)= *a * *b + *(a+1) * *(b+1) + Do
19、tProduct:result(a+2,b+2)= *a * *b + *(a+1) * *(b+1) + *(a+2) * *(b+2) + DotProduct:result(a+3,b+3)= *a * *b + *(a+1) * *(b+1) + *(a+2) * *(b+2) + *(a+3) * *(b+3) + DotProduct:result(a+4,b+4)= *a * *b + *(a+1) * *(b+1) + *(a+2) * *(b+2) + *(a+3) * *(b+3) + *(a+4) * *(b+4)值得一提的一個(gè)模板元編程陷阱長期以來,科學(xué)計(jì)算領(lǐng)域一直是F
20、ortran的天下,采用運(yùn)行期C+實(shí)現(xiàn)的算法太慢而無法適應(yīng)數(shù)值計(jì)算的要求,利用元編程、表達(dá)式模板以及更好的編譯器、優(yōu)化器,現(xiàn)代C+也可以很好地滿足數(shù)值計(jì)算的要求。數(shù)值計(jì)算Todd Veldhuizen對(duì)C+和Fortran在科學(xué)計(jì)算領(lǐng)域的性能表現(xiàn)作了比較 (參見注4) 。實(shí)踐證明,對(duì)于現(xiàn)代C+編程而言,元編程最大的用場本并不在于編譯期數(shù)值計(jì)算,而是用于類型計(jì)算(type computation)(及相關(guān)領(lǐng)域)。通過類型參數(shù)、模板參數(shù)、typedef、枚舉(或靜態(tài)整型常量)以及內(nèi)嵌類(模板)成員等,借助于靈活的類模板特化能力,模板元編程在類型計(jì)算方面可以釋放出極大的能量。類型計(jì)算類型計(jì)算/ 僅聲
21、明struct Nil;/ 主模板template struct IsPointer enum Result = false ; typedef Nil ValueType;/ 局部特化template struct IsPointer enum Result = true ; typedef T ValueType;/ 示例int main() cout IsPointer:Result endl; cout IsPointer:Result endl; IsPointer:ValueType i = 1; /IsPointer:ValueType j = 1; / 錯(cuò)誤:使用未定義的類型N
22、il可以依樣實(shí)現(xiàn)出IsReference、IsClass、IsFloat、IsMemberPointer等元函數(shù),事實(shí)上,Boost Type Traits庫提供了數(shù)十個(gè)類似的元函數(shù)以及像add_reference這樣的低級(jí)類型操縱元函數(shù),用于偵測(cè)、處理類型的基本屬性。該庫已經(jīng)被納入C+標(biāo)準(zhǔn)委員會(huì)技術(shù)報(bào)告(Technical Report),這預(yù)示著它將會(huì)進(jìn)入C+0 x標(biāo)準(zhǔn)。前述的“循環(huán)開解”實(shí)際上就是一種代碼生成機(jī)制,但模板元編程代碼生成機(jī)制的作用并不局限于數(shù)值計(jì)算領(lǐng)域。代碼生成struct A static void execute() cout A endl; ;struct B sta
23、tic void execute() cout B endl; ;int main() IfThenElse:ResultType:execute();模板元程序充任“高級(jí)的預(yù)處理指令”等價(jià)template struct ScatterHierarchyTag;template class TList, template class Unit struct GenScatterHierarchy;/見下頁前述的“循環(huán)開解”實(shí)際上就是一種代碼生成機(jī)制,但模板元編程代碼生成機(jī)制的作用并不局限于數(shù)值計(jì)算領(lǐng)域。代碼生成此例摘自Loki&MCDstruct Nil; / 僅聲明struct Em
24、pty;/ Typelisttemplate struct TypeList typedef H Head; typedef T Tail;模板也是一種元數(shù)據(jù)代碼生成/ 接上template class T1, class T2, template class Unitstruct GenScatterHierarchyTypeList, Unit : public GenScatterHierarchyScatterHierarchyTag, Unit , public GenScatterHierarchy;template class T1, class T2, template cla
25、ss Unitstruct GenScatterHierarchyScatterHierarchyTag, Unit : public GenScatterHierarchy;template class AtomicType, template class Unitstruct GenScatterHierarchy : public Unit;template template class Unitstruct GenScatterHierarchy;處理Nil類型的情況什么都不做將一個(gè)非Typelist的原子類型傳給Unit代碼生成/ 自定義類型Teststruct Test enum
26、Value = 100;template struct Holder T Value; static void f() cout sizeof(T) endl; / .;/ 定義一個(gè)包含有char、int、Test和float的Typelisttypedef TypeListchar, TypeListint, TypeListTest, TypeList CIRF;typedef GenScatterHierarchy SH;這個(gè)Holder模板決定了生成的各個(gè)類的能力代碼生成int main() SH sh; cout (dynamic_castHolder&(sh).Value
27、= a) endl; cout (dynamic_castHolder&(sh).Value = 1) endl; cout (dynamic_castHolder&(sh).Value = 3.14f) endl; cout (dynamic_castHolder&(sh).Value.Value) endl; / cout (dynamic_castHolder&(sh).Value = 3.14) endl;GenScatterHierarchy將給定的TypeList中的每一個(gè)類型施加于一個(gè)由用戶提供的基本模板Holder上,從而產(chǎn)生一個(gè)類層次結(jié)構(gòu)。換句
28、話說,生成的各類的能力,取決于客戶提供的Holder模板的能力。示例中生成了一個(gè)多重繼承類層次結(jié)構(gòu),Holder, Holder, Holder, Holder之間沒有任何關(guān)系,但它們都是SH的基類,即所產(chǎn)生的SH層次結(jié)構(gòu)其實(shí)相當(dāng)于:class SH: public Holder, public Holder, public Holder, public Holder;代碼生成利用元編程生成類層次結(jié)構(gòu)最大的好處在于其靈活性:TypeList是可擴(kuò)展的,其長度不但可以任意定制,而且對(duì)其更改后SH可以自適應(yīng)地產(chǎn)生新的代碼。Loki庫中的Abstract Factory泛型模式即借助于這種機(jī)制實(shí)現(xiàn)在
29、不損失類型安全性的前提下降低對(duì)類型的靜態(tài)依賴性。進(jìn)一步了解typelist和相關(guān)的代碼生成技術(shù),以及Abstract Factory泛型模式,參見注11和注15??梢岳迷幊碳夹g(shù)實(shí)現(xiàn)編譯期斷言和編譯期約束 。斷言和契約斷言用于指定程序中某些特定點(diǎn)的條件應(yīng)為“真”。如果該條件不為真,則斷言失敗,程序執(zhí)行中斷。大量使用斷言可以在開發(fā)期捕捉許多錯(cuò)誤。當(dāng)然,若有可能,在編譯期抓住錯(cuò)誤更好。觸發(fā)編譯期斷言的結(jié)果是導(dǎo)致程序無法通過編譯。編譯期斷言的實(shí)現(xiàn)方式并非僅限于模板元編程一種。斷言和契約/主模板templatestruct StaticAssert;/ 完全特化template struct Sta
30、ticAssert;/ 輔助宏#define STATIC_ASSERT(exp) StaticAssert StaticAssertFailed; int main() STATIC_ASSERT(01);聲明STATIC_ASSERT宏是為了方便使用,否則用戶如果寫StaticAssert;在有些編譯器(例如GCC和Borlad C+)中編譯報(bào)錯(cuò),在另外一些編譯器(例如VC+和Digital Mars)中則可以編譯通過。也就是說,單單“提及”一下StaticAssert是不保險(xiǎn)的,要強(qiáng)迫它完全實(shí)例化才能保證觸發(fā)斷言,例如StaticAssert S;這看上去有些臆怪,因此我們把它封裝到宏里
31、:StaticAssert StaticAssertFailed;斷言和契約命名為StaticAssertFailed是為了便于在生成的編譯錯(cuò)誤信息中看出觸發(fā)了一個(gè)靜態(tài)斷言,例如在GCC中生成如下錯(cuò)誤信息:sa.cpp:13: error: aggregate StaticAssert StaticAssertFailed has incomplete type and cannot be defined注意:表達(dá)式必須能夠在編譯期進(jìn)行求值,無法對(duì)運(yùn)行期表達(dá)式進(jìn)行求值。這個(gè)錯(cuò)誤信息還有改善的余地,你可以考察Boost和Loki中的靜態(tài)斷言庫/組件,它們的實(shí)現(xiàn)更到位。一個(gè)新的關(guān)鍵字static_
32、assert極有可能被加入C+0 x,其作用正如StaticAssert模板。斷言和契約契約式設(shè)計(jì)(Design by Contract)要求為組件指定“契約”,這些契約會(huì)在程序運(yùn)行過程中的某些特定點(diǎn)被強(qiáng)制執(zhí)行。編譯期契約也被稱為約束(constraints)。C+雖然不直接支持約束,但是我們可以手工實(shí)現(xiàn)這項(xiàng)技術(shù)。例如,結(jié)合運(yùn)用上述StaticAssert和前面編寫的IsPointer,可以實(shí)現(xiàn)一個(gè)約束:#define CONSTRAINT_MUST_BE_POINTER(T) STATIC_ASSERT(IsPointer:Result != 0)斷言和契約在以下類模板中,通過將該約束放在析
33、構(gòu)函數(shù)中,通??梢员WC模板參數(shù)T必須是一個(gè)指針類型:template class Testpublic: Test() / 只要該類的實(shí)例被創(chuàng)建,約束就會(huì)發(fā)揮作用 CONSTRAINT_MUST_BE_POINTER(T); ;我們沒有將它放置于構(gòu)造函數(shù)中,因?yàn)闃?gòu)造函數(shù)可能不止一個(gè)int main() Test r; / OK Test d; / 違反約束,編譯報(bào)錯(cuò)庫C+模板的語法較復(fù)雜,一些慣用法應(yīng)該采用庫的方式提供。將這些復(fù)雜性封裝于庫中,并暴露給用戶友好的接口,是每一個(gè)模板庫開發(fā)者的責(zé)任,因?yàn)樵購?fù)雜的庫都應(yīng)該是“面向用戶”的。庫中出現(xiàn)大量的繁雜的代碼是可以接受的,因?yàn)檫@樣的工作只需做一次
34、,而所有庫的用戶均可從中受益。高質(zhì)量的庫可以為開發(fā)可移植、高性能的應(yīng)用提供良好的基礎(chǔ),一個(gè)經(jīng)過縝密設(shè)計(jì)和測(cè)試的庫具有良好的復(fù)用性,可以屏蔽平臺(tái)之間的差異,可以使程序員專注于自己的業(yè)務(wù)開發(fā)。知名的模板元編程庫有Loki 注14 、Boost (元編程庫)注13 、Blitz+ 注15以及MTL 注16等。庫Blitz+ 核心庫的開發(fā)者是模板元編程技術(shù)的創(chuàng)始人Todd Veldhuizen,可以說是最早利用模板將運(yùn)行期計(jì)算轉(zhuǎn)移至編譯期的庫,主要提供了對(duì)向量、矩陣等進(jìn)行處理的線性代數(shù)計(jì)算。長期以來,科學(xué)計(jì)算一直是Fortran77/90的地盤,而Blitz+利用元編程(以及表達(dá)式模板等)技術(shù)可以獲得
35、和Fortran77/90媲美的效率(參見注4)。Loki 將模板元編程在類型計(jì)算方面的威力應(yīng)用于設(shè)計(jì)模式領(lǐng)域,利用元編程(以及其他一些重要的設(shè)計(jì)技術(shù))實(shí)現(xiàn)了一些常見的設(shè)計(jì)模式之泛型版本。庫Boost 元編程庫目前主要包含MPL、Type Traits和Static Assert等庫。 Static Assert和Type Traits用作MPL的基礎(chǔ)。MPL是一個(gè)通用的模板元編程框架,它仿照STL提供了編譯期算法、序列、迭代器等元編程組件。它為普通程序員進(jìn)行元編程提供了高級(jí)抽象,使得元編程變得容易、高效、富有樂趣。Boost Type Traits庫包含一系列traits類,用于萃取C+類型
36、特征。另外還包含了一些轉(zhuǎn)換traits(例如移除一個(gè)類型的const修飾符等)。Boost Static Assert庫用于編譯期斷言,如果評(píng)估的表達(dá)式編譯時(shí)計(jì)算結(jié)果為true,則代碼可以通過編譯,否則編譯報(bào)錯(cuò)。DSEL對(duì)于領(lǐng)域特定的嵌入式語言(domain-specific embedded language, DSEL)的設(shè)計(jì)者而言, 模板元編程技術(shù)是一件利器。這里的DSEL就是庫,例如一些圖形或矩陣計(jì)算庫都可被認(rèn)為是一種小型語言:其接口定義語法,其實(shí)現(xiàn)定義語義。它們均提供了領(lǐng)域特定的符號(hào)、構(gòu)造和抽象。利用模板元編程技術(shù)構(gòu)建的DSEL,高效且語法接近于從頭構(gòu)建的語言。由于這種DSEL采用純
37、粹的C+編寫,與使用獨(dú)立的DSL相比,無需再使用專門的編譯器、編輯器等工具,從而可以消除跨語言邊界所需付出的代價(jià)。如欲進(jìn)一步了解采用C+模板元編程實(shí)現(xiàn)DSEL,參見注9。DSELint a510;int i;for_each(a, a+5, for_loop(var(i)=0, var(i)10, +var(i), _1var(i) += 1) ); std:for_each(v.begin(), v.end(), (switch_statement(_1, case_statement(std:cout constant(zero), case_statement(std:cout cons
38、tant(one), default_statement(cout constant(other: ) _1) ), cout constant(n) ) );摘自Boost Lambda庫的幾個(gè)例子:DSELfor_each( a.begin(), a.end(), try_catch( bind(foo, _1), / foo may throw catch_exception ( cout constant(Caught foo_exception: ) foo was called with argument = _1 ), catch_exception ( cout constan
39、t(Caught std:exception: ) bind(&std:exception:what, _e), throw_exception(bind(constructor(), _1) ), catch_all(cout constant(Unknown), rethrow() ) ) );結(jié)語模板元程序與常規(guī)代碼結(jié)合使用時(shí),此時(shí)源代碼包含兩種程序:常規(guī)C+運(yùn)行期程序和編譯期運(yùn)行的模板元程序。當(dāng)被編譯器解釋時(shí),模板元程序可以生成高效的代碼,從而可以大幅提高最終應(yīng)用程序的運(yùn)行效率。通過將計(jì)算從運(yùn)行期轉(zhuǎn)移至編譯期,在結(jié)果程序啟動(dòng)之前做盡可能多的工作,最終獲得速度更快的程序。模板元編
40、程也有一些局限性,使用模板元編程時(shí)(尤其使用模板元編程進(jìn)行數(shù)值計(jì)算時(shí))存在一些注意事項(xiàng)調(diào)試?yán)щy:元程序執(zhí)行于編譯期,沒有用于單步跟蹤元程序執(zhí)行的調(diào)試器(用于設(shè)置斷點(diǎn)、察看數(shù)據(jù)等)。程序員可做的只能是等待編譯過程失敗,然后人工破譯編譯器傾瀉到屏幕上的錯(cuò)誤信息。 代碼的可讀性較差。結(jié)語結(jié)果程序性能未必一定最優(yōu)化:“循環(huán)開解”技術(shù)要有選擇地使用,具體獲得的效果必須進(jìn)行評(píng)測(cè)。倘若代碼展開導(dǎo)致程序尺寸過大,可能會(huì)降低cache的命中率,未必會(huì)帶來性能上的提高。編譯器局限性:模板的實(shí)例化通常要占用不少編譯器資源,大量的遞歸實(shí)例化會(huì)迅速拖慢編譯器甚至耗盡可用資源。編譯時(shí)間延長:元程序被編譯器解釋執(zhí)行的,C+編譯器并不是一個(gè)好的解釋器??梢浦残暂^差:對(duì)于模板元編程使用的高級(jí)模板特性,不同的編譯器的支持度不同。資源以下是一些C+模板元編程資源,它們或者為本幻燈片的制作提供了參考素材,或者提供了延伸知識(shí)。2 Todd Veldhuizen, Expression Templates, /tveldhui/papers/Expression-Templates/exprtmpl.html1 Todd Veldhuize
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 餡餅制作教學(xué)課程設(shè)計(jì)
- 美術(shù)畢業(yè)課程設(shè)計(jì)
- 基于mapreduce的課程設(shè)計(jì)
- 純凈水檢測(cè)課程設(shè)計(jì)
- 螺紋蓋塑料課程設(shè)計(jì)
- 通信原理ssb課程設(shè)計(jì)
- 鑄造工藝學(xué)課程設(shè)計(jì)懸梁
- 餅干造型手工課程設(shè)計(jì)
- 運(yùn)輸成本課程設(shè)計(jì)
- 鍛造 專業(yè) 課程設(shè)計(jì)
- 醫(yī)療組長競聘
- 2024年業(yè)績換取股權(quán)的協(xié)議書模板
- 顳下頜關(guān)節(jié)疾?。谇活M面外科學(xué)課件)
- 工業(yè)自動(dòng)化設(shè)備維護(hù)保養(yǎng)指南
- 2024人教新版七年級(jí)上冊(cè)英語單詞英譯漢默寫表
- 《向心力》參考課件4
- 2024至2030年中國膨潤土行業(yè)投資戰(zhàn)略分析及發(fā)展前景研究報(bào)告
- 2024年深圳中考數(shù)學(xué)真題及答案
- 土方轉(zhuǎn)運(yùn)合同協(xié)議書
- Module 3 Unit 1 Point to the door(教學(xué)設(shè)計(jì))-2024-2025學(xué)年外研版(三起)英語三年級(jí)上冊(cè)
- 智能交通信號(hào)燈安裝合同樣本
評(píng)論
0/150
提交評(píng)論