看了546@C++@Freecity之后,發(fā)覺(jué)非常有意思,由此產(chǎn)生一些想法
很多時(shí)候?qū)懸粋€(gè)類的時(shí)候,需要多個(gè)模版參數(shù),例如一個(gè)遺傳算法的算法類,需要一個(gè)模版參數(shù)來(lái)指定交配方式,另一個(gè)模版參數(shù)來(lái)指定子代選擇的方式,還要一個(gè)參數(shù)來(lái)指定變異的方式。那么一般來(lái)說(shuō),這個(gè)類會(huì)寫(xiě)成:
template<class T //描述問(wèn)題的一個(gè)類
, class CrossPolicy = AvgCrossPolicy //雜交方式
, class SelectPolicy = DefaultSelectPolicy //子代選擇的方式
, class VariationPolicy = ReverseVariationPolicy> //變異方式
class Gene
: private AvgCrossPolicy
, private SelectPolicy
, private VariationPolicy
{
....
};
這樣用戶要使用該類的時(shí)候,可以直接指定T,就行了,然而如果要指定變異方式,那么就必須把所有的參數(shù)都顯式的寫(xiě)出來(lái),很不方便
546提供了一種有效的方法,可以讓我們僅僅指定變異參數(shù),而不用寫(xiě)出另兩個(gè)Policy
甚至允許我們以任意的順序書(shū)寫(xiě)幾個(gè)Policy參數(shù),都不會(huì)有問(wèn)題
預(yù)備知識(shí):
TypeList
一個(gè)TypeList是一個(gè)類型的容器
template <typename Type_, typename Next_>
struct TypeList
{
typedef Type_ Type;
typedef Next_ Next;
};
這就是一個(gè)TypeList。
看這個(gè)寫(xiě)法,是不是像一個(gè)鏈表?
首先定義一個(gè)類型來(lái)表示鏈表尾:class NullType{};
現(xiàn)在一個(gè)包含了2個(gè)類型的TypeList就可以寫(xiě)為:
TypeList<T1, TypeList<T2, NullType> >
如何在一個(gè)TypeList中查找一個(gè)類型的子類?
首先要有一個(gè)IsDerivedFrom<Base, T>
這個(gè)比較簡(jiǎn)單
template<class Base, class T>
class IsDerivedFrom
{
struct large{char a[2];};
static char pred(Base*);
static large pred(...);
public:
enum {Is = sizeof(pred((T*)0)) == sizeof(char)};
};
然后FindChild就容易了
template <class List, class Base>
struct FindChild
{
template <bool IsChild>
struct Select
{
typedef typename List::Type Type;
};
template <>
struct Select<false>
{
typedef typename FindChild<typename List::Next, Base>::Type Type;
};
typedef typename Select<IsDerivedFrom<Base, typename List::Type> >::Type Type;
};
當(dāng)然還要對(duì)一些特殊情況進(jìn)行特化,例如NullType
template <class Base>
struct FindChild<NullType, Base>
{
typedef NullType Type;
};
這里使用NullType來(lái)表明沒(méi)找到
實(shí)際操作:
首先需要給3個(gè)Policy3個(gè)基類,分別叫
class AvgCrossPolicyBase{};
class SelectPolicyBase{};
class VariationPolicyBase{};
內(nèi)容為空就行了,這樣也沒(méi)有虛函數(shù)調(diào)用的開(kāi)銷
然后聲明一個(gè)類來(lái)表示默認(rèn)情況:
class DefaultPolicy{};
定義一個(gè)宏
#define TYPELIST_3_N(a, b, c) TypeList<a, TypeList<b, TypeList<c, NullType> > >
下面要寫(xiě)一些選擇器,用于把合適的類型選擇出來(lái),如果沒(méi)找到,則要使用默認(rèn)的類型
template <class List, class Base, class DefaultType>
struct Selector
{
template <class RetType>
struct Judge
{
typedef RetType Type;
};
template<>
struct Judge<NullType>
{
typedef DefaultType Type;
};
typedef typename Judge<typename FindChild<List, Base>::Type >::Type Type;
};
好啦,現(xiàn)在整個(gè)類的聲明可以寫(xiě)為
template<class T
, class CrossPolicy_ = DefaultPolicy
, class SelectPolicy_ = DefaultPolicy
, class VariationPolicy_ = DefaultPolicy //其后的參數(shù)用戶不可指定
, class List = TYPELIST_3_N(CrossPolicy_, SelectPolicy_, VariationPolicy_)
, class CrossPolicy = typename Selector<List, CrossPolicyBase, AvgCrossPolicy>::Type
, class SelectPolicy = typename Selector<List, SelectPolicyBase, DefaultSelectPolicy>::Type
, class VariationPolicy = typename Selector<List, VariationPolicyBase, ReverseVariationPolicy>::Type
>
class Gene
: private CrossPolicy
, private SelectPolicy
, private VariationPolicy
{
....
};
其中第4-7個(gè)參數(shù)(List,CrossPolicy,SelectPolicy和VariationPolicy)是不由用戶指定的,僅僅是為了起一個(gè)別名
第一個(gè)參數(shù)T必須指定,然后2,3,4這3個(gè)參數(shù)就可以任意的改變順序了
例如,可以寫(xiě)Gene<T, DefaultSelectPolicy, AvgCrossPolicy>而不會(huì)有任何問(wèn)題
如果不想要最后面幾個(gè)參數(shù)的話也行,但是代碼就要稍微長(zhǎng)一點(diǎn)
而且最好在類里面進(jìn)行3個(gè)typedef
typedef typename Selector<List, CrossPolicyBase, AvgCrossPolicy>::Type CrossPolicy;
等,以便在實(shí)現(xiàn)的時(shí)候使用
posted on 2006-07-24 01:06
shifan3 閱讀(1010)
評(píng)論(9) 編輯 收藏 引用 所屬分類:
template 、
C++