《Modern C++ Design》Loki庫源碼讀解隨想
大牛Andrei Alexandrescu的《Modern C++ Design》討論的是C++語言的最前沿研究:generative programming。本書中譯版估計得要半年以後才能出來,所以只能靠其所附源碼來窺測generative programming了。
目前,我剛將源碼讀解了約一半,等全部讀完,我會將我的讀解注釋放出來的。現在,現談一下我的感想。
先扯得遠一點。C++有兩個巨大優點:和C相容,自由;有兩個巨大缺點:和C相容,複雜。C++極其複雜,很難掌握,而這正是“自由”的代價。C++語言是個多編程風格的語言,它同時支援過程化、基於對象、物件導向、泛型、產生性這5種編程思想,具有極其強大的表達能力,可以方便地將各種設計轉化為實現。
generic Programming的思想精髓是基於介面編程(相對於OOP,連多態所需的基類都不要了),它的技術出發點是選擇子,核心技術是:類型推導、類型萃取、特化/偏特化,其成果是STL庫:一組通用容器和一組操作於通用容器上的通用演算法。
generative programming的思想精髓是基於策略編程(編譯器根據策略自動產生所需代碼,由於具有更高的抽象性,所以代碼複用度也更高),在Loki庫的實現中,目前只使用了遞迴策略,它的技術出發點是Typelist,核心技術是:類型推導、類型萃取、特化/偏特化、多重繼承、類型間去耦合,其成果是Loki庫:對設計模式的封裝。
Typelist是一種對類型本身進行儲存和管理的技巧,它的源碼已經貼過了,我也作了註解,此處不再談論。
這是多重繼承在COM之後的又一大型運用。多重繼承極易發生菱型缺陷,所以Loki庫使用了類型間去耦合技術來避免:
template <typename T>
struct Type2Type
{
typedef T OriginalType;
};
經過這樣一層轉換後,原類型T間的各種轉換關係(尤其是繼承/派生關係)已不複存在,菱型缺陷不會再發生了。
Loki庫的具體實現相當講究技巧,設計它非常困難(難度遠大於STL庫,和Boost庫有得一拼啊)。但使用它卻非常容易,而且便利顯著。由於Loki庫提供了對設計模式的封裝,所以極大量地豐富了C++語言的表達能力,使的你的設計更容易地轉化為實現。
目前,Loki庫只提供了對廠模式和visitor模式的封裝,它還處於發展初期。
我以visitor模式為例,講解Loki庫提供的便利。
Visitor模式有四種實現方式:1一串RTTI的類型判斷;2二次調度(double dispatch);3建立類型與處理函數的對應表;4非迴圈visitor(Acyclic Visitor)。在《More Effective C++》 Item 31中討論了前3種實現(雖然它的例子本身不太算visitor模式的)。第四種方式在《使用設計模式改善程式結構》(二)(http://www-900.ibm.com/developerWorks/cn/java/l-dpstruct/part2/index.shtml)中有詳細講解。
原型圖
以這張原型圖而言,使用者需要自己實現大量的代碼,而且,由於使用多重繼承技術,在具體Host類間有繼承關係時,它一定會發生問題。
Loki庫實現圖
使用Loki庫,使用者實現visitor模式時只需:讓Host類從BaseVisitable繼承,並在所有衍生類別中加上DEFINE_VISITABLE()宏,讓所有Visitor類從BaseVisitor類和VisitorImpl類進行二重繼承(並且可以只提供對自己感興趣的Host類的處理函數,不感興趣的不提供處理函數)。使用者的工作量非常小、非常簡單,設計人員可以不用為實現而分心了。
更重要的是,由於採用了類型間去耦合技術,多個Host之間存在繼承關係時,不會發生問題(其具體實現較複雜,於是我在UML圖上作了模糊處理,沒有展示出來,留在以後Loki庫源碼讀解時講述)。