Typelists
Typelists是一個用來操作一大群型別的C++工具。就像list對數值提供的各種基本操作一樣,typelists對型別也提供相同的操作。
有些設計模式具體制定并操作一群型別,其中也許有繼承關系,顯著的例子是abstract factory和visitor。如果以傳統編程技術來操作一大群型別,將式全然重復的工作,如此重復將會導致隱微的代碼膨脹。多數人不會想到其實它可以比現在更好。Typelists帶給你一種能力,可以講將經常性的宏工作自動化。Typelists將來自外星球的巨大威力帶到C++中,讓它得以支持新而有趣的一些手法。
?
3.1 Typelists的必要性
有時候你必須針對某些型別重復撰寫相同代碼,而templates無法幫上忙。假如有一個abstract factory,像這樣:
class WidgetFactory { public:virtual Window* CreateWindow() = 0;virtual Button* CreateButton() = 0;virtual ScrollBar* CreateScrollBar() = 0; };如果想將abstract factory概念泛化,不止生成window、bottom、scrollbar,而是任意型別。怎么辦?
如果你不試圖泛化基本概念,就不太會有機會泛化這些概念的具體實體,雖然抽象基類很簡單,但是你會陷入無窮無盡的派生類生成器中。
我們希望能夠這樣去使用一個abstract factory:
template<class T> T* MakedWidget(WidgetFactory& factory) {T* pW=factory.create<T>();pW=SetColor(RED);return pW; }實際這是不可能的,如果Create不是虛函數,那么你就陷入了長長的Switch...case...之中,如果它是虛函數,那么虛函數不能是模板。
Typelists將使Abstract Factories泛化成真,并帶來更多其它利益。
?
定義Typelists
template< class T,class U> struct Typelist {typedef T head;typedef T Tail; };Typelists 內部沒有任何數值:他的實體是空的。它們存在的理由只是為了攜帶型別信息。因此,對Typelists的任何處理都發生在編譯期。此后我們提到一個typelist,指的是一個型別而非一個對象。雖然typlist只有兩個參數,但我們可以把任意一個替換為另一個typelist,來達到無限延伸的目的。
另外我們需要一個0型別以及一個型別的Typelists,對于0型別,前面提到的NullType就可以,對于一個型別,我們可以這樣定義:
typedef Typelist<int ,NullType> oneTypeOnly;
將Typelist生成線性化
像這樣一個Typelist
typedef Typlist<int, Typelist<int, Typelist<int, Typelist<int, int> > > > Int4Type;它太Lisp了,我們定義一系列的宏來完成它,這樣我們可以忘記尖括號間的空格。
#define TYPELIST_1(T1) Typelist<T1, NullType> #define TYPELIST_2(T1, T2) Typelist<T1, TYPELIST_1(T2) > #define TYPELIST_3(T1, T2, T3) Typelist<T1, TYPELIST_2(T2, T3) > #define TYPELIST_4(T1, T2, T3, T4) Typelist<T1, TYPELIST_3(T2, T3, T4) >//etc #define TYPELIST_50(/* */) //這樣前面的 Int4Type 就可以這樣定義
typedef Int4Type TYPELIST_4(int, int, int, int) Int4Type;這只是包裝手法的一個開端。我們訪問Int4Type的最后一個元素還比較麻煩,需要
Int4Type::Tail::Tail::Tail;
計算長度
我們用下面代碼來計算Typelist的長度
template<class TList>struct Length; template<> struct Length<NullType>{enum{value=0}; };template<class T,class U> struct Length<Typelist<T,U>> {enum{value=1+Length<U>::value}; };由Length<T>::value得到的是一個編譯期常數,我們可以用它來定義數組大小,
std::type_info* intsRtti[Length<SignedIntegrals>::value];這個模板代碼依靠遞歸來完成,第一個版本是全特化,第二個版本是偏特化。
?
間奏曲
這里有一個問題,在Length的實現中,我們能否用迭代來取代遞歸?答案是否定的。因為我們在編譯期編程中,可以使用到的僅僅是:template、編譯期整數計算、typedef。
1、template:更明確的說是模板特化,提供編譯期的if敘述。
2、整數計算:提供數值計算能力,用以從性別轉為數值,但數值是不可改變的。
3、typedef:可視為用來引進“具名的型別常數”,他們也是定義之后就凍結,你不能將typedef定義的符號重新定義為另一個型別。
?
這些特性決定了我們無法使用迭代,所謂迭代是持有一個迭代器,并改變它,知道某些條件吻合,由于編譯期我們沒有“可資變化的任何東西”,所以無法實現“迭代”。所以編譯期運算只能象那些純粹函數型語言,使用大量的遞歸。
?
索引式訪問
索引式訪問是Typelist訪問線性化,像在static世界中,索引必須是編譯期常數,一個帶有索引的template聲明如下:
template<class TList,unsigned int index> struct TypeAt;實現如下:
template<class Head,Class Tail> struct TypeAt<Typelist<Head,Tail>,0> {typedef Head Result; }template<class Head,class Tail,unsigned int> struct TypeAt<Typelist<Head,Tail>,i> {typedef typename TypeAt<Tail,i-1>::Reslut Result; }如果你試著越界訪問,會編譯出錯。對Typelist進行索引訪問,花費的時間和typelist大小有關,但這個時間全部花在編譯期。
?
查找Typelist
我們用index0f來查找Typelist中的一個型別,返回其位置,找不到就返回-1。
template <class TList, class T> struct IndexOf; template <class T> struct IndexOf<NullType, T>{enum{value = -1}; };template <class Tail, class T> struct IndexOf<Typelist<T, Tail>, T>{enum{value = 0;} };template <class Head, class Tail, class T> struct IndexOf<Typelist<Head, Tail>, T>{ private:enum{temp = IndexOf<Tail, T>::vale}; public:enum{value = temp == -1 ? -1 : 1+temp}; };最后一個特化版本是用了問號表達式來實現分支判斷
追加元素至Typelist
修改typelist是不可能的,我們以by value方式傳回一個新typelist。
template <class TList, class T> struct Append; template <> struct Append<NullType, NullType>{typedef NullType Result; }; template <class T> struct Append<NullType, T>{typedef TYPELIST_1(T) Result; }; template <class Head, class Tail> struct Append<NullType, Typelist<Head, Tail> >{typedef Typelist<Head, Tail> Result; }; template <class Head, class Tail, class T> struct Append<Typelist<Head, Tail>, T>{typedef Typelist<Head, typename Append<Tail,T>::Result> Result; };
這個實現比較復雜,特別是最后一個偏特化版本,他遞歸具現Append,每次遞歸都將tail和待追加型別傳遞進去
?
移除typelist中的某個元素
template <class TList, class T> struct Erase; template <class T> struct Erase<NullType, T>{typedef NullType Result; }; template<class T, calss Tail> struct Erase<Typelist<T, Tail> T>{typedef Tail Result; }; template <class Head, class Tail, class T> struct Erase<Typelist<Head, Tail>, T>{typedef Typelist<Head,typename Erase<Tail, T>::Result>Result; };
?
轉載于:https://www.cnblogs.com/chillblood/p/4087542.html
總結
- 上一篇: C++中this指针的使用方法.
- 下一篇: 添加Godaddy二级域名子域名方法