看了546@C++@Freecity之后,发觉非常有意思,由此产生一些想法
很多时候写一个类的时候,需要多个模版参数,例如一个遗传算法的算法类,需要一个模版参数来指定交配方式,另一个模版参数来指定子代选择的方式,还要一个参数来指定变异的方式。那么一般来说,这个类会写成:
template<class T //描述问题的一个类
, class CrossPolicy = AvgCrossPolicy //杂交方式
, class SelectPolicy = DefaultSelectPolicy //子代选择的方式
, class VariationPolicy = ReverseVariationPolicy> //变异方式
class Gene
: private AvgCrossPolicy
, private SelectPolicy
, private VariationPolicy
{
....
};
这样用户要使用该类的时候,可以直接指定T,就行了,然而如果要指定变异方式,那么就必须把所有的参数都显式的写出来,很不方便
546提供了一种有效的方法,可以让我们仅仅指定变异参数,而不用写出另两个Policy
甚至允许我们以任意的顺序书写几个Policy参数,都不会有问题
预备知识:
TypeList
一个TypeList是一个类型的容器
template <typename Type_, typename Next_>
struct TypeList
{
typedef Type_ Type;
typedef Next_ Next;
};
这就是一个TypeList。
看这个写法,是不是像一个链表?
首先定义一个类型来表示链表尾:class NullType{};
现在一个包含了2个类型的TypeList就可以写为:
TypeList<T1, TypeList<T2, NullType> >
如何在一个TypeList中查找一个类型的子类?
首先要有一个IsDerivedFrom<Base, T>
这个比较简单
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;
};
当然还要对一些特殊情况进行特化,例如NullType
template <class Base>
struct FindChild<NullType, Base>
{
typedef NullType Type;
};
这里使用NullType来表明没找到
实际操作:
首先需要给3个Policy3个基类,分别叫
class AvgCrossPolicyBase{};
class SelectPolicyBase{};
class VariationPolicyBase{};
内容为空就行了,这样也没有虚函数调用的开销
然后声明一个类来表示默认情况:
class DefaultPolicy{};
定义一个宏
#define TYPELIST_3_N(a, b, c) TypeList<a, TypeList<b, TypeList<c, NullType> > >
下面要写一些选择器,用于把合适的类型选择出来,如果没找到,则要使用默认的类型
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;
};
好啦,现在整个类的声明可以写为
template<class T
, class CrossPolicy_ = DefaultPolicy
, class SelectPolicy_ = DefaultPolicy
, class VariationPolicy_ = DefaultPolicy //其后的参数用户不可指定
, 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个参数(List,CrossPolicy,SelectPolicy和VariationPolicy)是不由用户指定的,仅仅是为了起一个别名
第一个参数T必须指定,然后2,3,4这3个参数就可以任意的改变顺序了
例如,可以写Gene<T, DefaultSelectPolicy, AvgCrossPolicy>而不会有任何问题
如果不想要最后面几个参数的话也行,但是代码就要稍微长一点
而且最好在类里面进行3个typedef
typedef typename Selector<List, CrossPolicyBase, AvgCrossPolicy>::Type CrossPolicy;
等,以便在实现的时候使用
posted on 2006-07-24 01:06
shifan3 阅读(992)
评论(9) 编辑 收藏 引用 所属分类:
template 、
C++