一个类似DoubleDispatch的实现 看完了第三章。想起ChenA的那个问题。正好需要阶段性的总结。就实现一个比较完全的DoubleDispatch看看。也作为作业练习下。
基本的,客户手动修改越少越好,仍然用函数,而不是functor。
尽量尊重非MP的习惯。
首先是前三章的工具,这里用到的。主要是TypeList列表和相关的类型操作。 代码: //判断T是否base of U
#define SUPERSUBCLASS(T,U) \
(Conversion<const U*,const T*>::exists\
&&!Conversion<const T*, const void*>::sameType)
//判断T U是否可以转换
template<class T,class U>
struct Conversion
{
protected:
typedef char Small;
class Big{char dummy[2];};
static Small Test(U);
static Big Test(...);
static T MakeT();
public:
enum{exists=sizeof(Test(MakeT()))==sizeof(Small)};
enum{sameType=false};
};
template<class T>
struct Conversion<T,T>
{
public:
enum{exists=true};
enum{sameType=true};
};
//从T,U中选取
template<bool flag,typename T,typename U>
struct Select
{
typedef T Result;
};
template<typename T,typename U>
struct Select<false,T,U>
{
typedef U Result;
};
//TypeList和相关的工具
class NullType{};//不能是任何类的基类
template<class T,class U>
struct TypeList
{
typedef T Head;
typedef U Tail;
};
//Length获取TList的长度
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};
};
//IndexOf 获取T在TList中的序号
template<class TList,class T> struct IndexOf;
template<class T>
struct IndexOf<NullType,T>
{
enum{value=-1};
};
template<class T,class Tail>
struct IndexOf<TypeList<T,Tail>,T>
{
enum{value=0};
};
template<class Head,class Tail,class T>
struct IndexOf<TypeList<Head,Tail>,T>
{
private:
enum{v1=IndexOf<Tail,T>::value};
public:
enum{value=v1==-1?-1:1+v1};
};
//Replace将TList中的第一个T置换为U
template<class TList,class T,class U> struct Replace;
template<class T,class U>
struct Replace<NullType,T,U>
{
typedef NullType Result;
};
template<class T,class Tail,class U>
struct Replace<TypeList<T,Tail>,T,U>
{
typedef TypeList<U,Tail> Result;
};
template<class Head,class Tail,class T,class U>
struct Replace<TypeList<Head, Tail>, T, U>
{
typedef TypeList<Head,typename Replace<Tail,T,U>::Result> Result;
};
//Erase 从TList中删除第一个T
template<class TList,class T> struct Erase;
template<class T>
struct Erase<NullType,T>
{
typedef NullType Result;
};
template<class T,class 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;
};
//MostDerived 从TList获取最大的Derived of T
template<class TList,class T> struct MostDerived;
template<class T>
struct MostDerived<NullType,T>
{
typedef T Result;
};
template<class Head,class Tail,class T>
struct MostDerived<TypeList<Head,Tail>,T>
{
private:
typedef typename MostDerived<Tail,T>::Result T1;
public:
typedef typename Select<SUPERSUBCLASS(T1,Head),Head,T1>::Result Result;
};
//DerivedToFront 将TList调整为继承 偏序
template<class T> struct DerivedToFront;
template<>
struct DerivedToFront<NullType>
{
typedef NullType Result;
};
template<class Head,class Tail>
struct DerivedToFront<TypeList<Head,Tail> >
{
private:
typedef typename MostDerived<Tail,Head>::Result T1;
typedef typename Replace<Tail,T1,Head>::Result L1;
public:
typedef TypeList<T1,L1> Result;
};
//NoDuplicates 将TList重复的删除
template<class TList> struct NoDuplicates;
template<> struct NoDuplicates<NullType>
{
typedef NullType Result;
};
template<class Head,class Tail>
struct NoDuplicates<TypeList<Head,Tail> >
{
private:
typedef typename NoDuplicates<Tail>::Result L1;
typedef typename Erase<L1,Head>::Result L2;
public:
typedef TypeList<Head,L2> Result;
}; 为了将指定的T的Supers从TypeList中提取,以及在两个TypeList中查找符合关系的两个Type,自己写了几个小工具。 代码: //ReserveSupers 从TList中只保留T和T的基类
template<class TList,class T> struct ReserveSupers;
template<class T>
struct ReserveSupers<NullType,T>
{
typedef NullType Result;
};
template<class Head,class Tail,class T>
struct ReserveSupers<TypeList<Head, Tail>,T>
{
private:
typedef typename ReserveSupers<Tail,T>::Result L1;
typedef TypeList<Head,L1> L2;
public:
typedef typename Select<SUPERSUBCLASS(Head,T),L2,L1>::Result Result;
};
//Supers 从TList中获取T的supers,偏序
template<class TList,class T> struct Supers
{
private:
typedef typename NoDuplicates<TList>::Result L1;
typedef typename ReserveSupers<L1,T>::Result L2;
public:
typedef typename DerivedToFront<L2>::Result Result;
};
//FindIf在TList中寻找符合Cond<T,U>::value==true的U
//结果value指示找到否,Result指示类型
template<class TList,class T,template<class T1,class T2> class Cond> struct FindIf;
template<template<class T1,class T2> class Cond>
struct FindIf<NullType,NullType,Cond>//空表中找空认为成功
{
enum{value=true};
typedef NullType Result;
};
template<class TList,template<class T1,class T2> class Cond>
struct FindIf<TList,NullType,Cond>//空元素和其他匹配,总是成功的
{
typedef NullType Result;
enum{value=true};
};
template<class T,template<class T1,class T2> class Cond>
struct FindIf<NullType,T,Cond>//空表中总是找不到非空元素
{
typedef T Result;
enum{value=false};
};
template<class Head,class Tail,class T,template<class T1,class T2> class Cond>
struct FindIf<TypeList<Head,Tail>,T,Cond>
{
typedef typename Select<Cond<T,Head>::value,
Head,typename FindIf<Tail,T,Cond>::Result>::Result Result;
enum{value=Cond<T,Head>::value||FindIf<Tail,T,Cond>::value};
};
//FindPairIf 获得符合条件的T1和T2在TList1中和TList2中
//返回Result1和Result2中(总会成功 至多 NullType NullType)
template<class TList1,class TList2,template<class T1,class T2> class Cond> struct FindPairIf;
template<class TList2,template<class T1,class T2> class Cond>
struct FindPairIf<NullType,TList2,Cond>
{
typedef NullType Result1;
typedef NullType Result2;
};
template<class Head,class Tail,class TList2,template<class T1,class T2> class Cond>
struct FindPairIf<TypeList<Head,Tail>,TList2,Cond>
{
private:
typedef FindIf<TList2,Head,Cond> T1;
typedef FindPairIf<Tail,TList2,Cond> T2;
public:
typedef typename Select<T1::value,Head,typename T2::Result1>::Result Result1;
typedef typename Select<T1::value,typename T1::Result,typename T2::Result2>::Result Result2;
}; 再这两堆工具的帮助下,实现了一个double dispatch的工具。(不知道怎么称呼这种东西,反正觉得叫类似乎不妥。) 代码: //调度用的工具
template<
class L1,class L2,template<class,class> class Cond,//在L1和L2中,以及判断需disp的条件Cond
class DispT,//dispT类型
template<class,class,class> class DispP//类型产生者
>
struct Dispatcher2
{
public:
Dispatcher2()
{
TableFiller<L1,L2> filltable;
filltable();
}
static DispT GetDisp(int i,int j){return disp_table[i][j];}
public:
template<class T> struct InnerID1{enum{value=IndexOf<L1,T>::value};};
template<class T> struct InnerID2{enum{value=IndexOf<L2,T>::value};};
private:
static DispT disp_table[Length<L1>::value][Length<L2>::value];
private:
//内部使用的模板类
//获取碰撞类型
template<class T,class U>
struct Pair
{
private:
typedef FindPairIf<typename Supers<L1,T>::Result,typename Supers<L2,U>::Result,Cond> T1;
public:
typedef typename T1::Result1 R1;
typedef typename T1::Result2 R2;
};
//填写一行的functor
template<class TList,class T> struct LineFiller;
template<class T> struct LineFiller<NullType,T>{void operator()(){}};
template<class Head,class Tail,class T>
struct LineFiller<TypeList<Head,Tail>,T>
{
void operator()()
{
int i=IndexOf<L1,T>::value;
int j=IndexOf<L2,Head>::value;
DispP<typename Pair<T,Head>::R1,typename Pair<T,Head>::R2,DispT> p;
disp_table[i][j]=p();
LineFiller<Tail,T> fillline;
fillline();
}
};
//填写整个表
template<class TList1,class TList2> struct TableFiller;//声明
template<class TList2> struct TableFiller<NullType,TList2>{void operator()(){}};//结束条件
template<class Head,class Tail,class TList2>//递归过程
struct TableFiller<TypeList<Head,Tail>,TList2>
{
void operator()()
{
LineFiller<TList2,Head> fillline;
fillline();
TableFiller<Tail,TList2> filltable;
filltable();
}
};
};
template<
class L1,class L2,template<class,class> class Cond,//在L1和L2中,以及判断需disp的条件Cond
class DispT,//dispT类型
template<class,class,class> class DispP//类型产生者
>
DispT Dispatcher2<L1,L2,Cond,DispT,DispP>::disp_table[Length<L1>::value][Length<L2>::value]; 最后看使用的代码。要自己手动填写类型表,自己实现virtual的ID1和ID2(当然它的具体实现属于Dispatch),自己提供一个Disp的类型,判断是否冲突的方法,产生Disp的方法。 代码: //这里是用户要填写的地方
class Base;
class A;
class B;
class C;
class D;
typedef
TypeList<A,
TypeList<B,
TypeList<D,
TypeList<D,
TypeList<C,
TypeList<Base,NullType> > > > > >
Colliders;//将Collider的类型手动填入这个表中可以重复但不要遗漏,Base可以不用写入
//定义了两个类型表//也可以放入Dispatcher中实现(typedef)
typedef DerivedToFront<NoDuplicates<Colliders>::Result>::Result CL1;
typedef CL1 CL2;
template<class T,class U> struct Colliderable{enum{value=false};};//判断是否冲突
template<class T,class U> void CollideImpl(Base*,Base*);//冲突实现
template<> struct Colliderable<NullType,NullType>{enum{value=true};};//缺省Null推出一切
template<> void CollideImpl<NullType,NullType>(Base*,Base*)
{throw std::runtime_error("Collide Not Impl.");}//缺省实现
template<> struct Colliderable<C,B>{enum{value=true};};//指示C,B的冲突
template<> void CollideImpl<C,B>(Base*,Base*)//C,B冲突实现
{std::cout<<"C,B"<<std::endl;}
typedef void (*COLLIDE)(Base*, Base*);
template<class T,class U,class R> struct CollideProvider;
template<class T,class U>
struct CollideProvider<T,U,COLLIDE>
{
COLLIDE operator()(){return CollideImpl<T,U>;}
};
//定义用户的dispatcher并且填好表
typedef Dispatcher2<CL1,CL2,Colliderable,COLLIDE,CollideProvider> CollideDispatcher;
CollideDispatcher collidedispather;//这里实际上也可以再封装,从而不需要再定义变量
class Base
{
public:
virtual int ID1(){return CollideDispatcher::InnerID1<Base>::value;};
virtual int ID2(){return CollideDispatcher::InnerID2<Base>::value;};
};
class A:public Base
{
public:
int ID1(){return CollideDispatcher::InnerID1<A>::value;};
int ID2(){return CollideDispatcher::InnerID2<A>::value;};
};
class B:public Base
{
public:
int ID1(){return CollideDispatcher::InnerID1[b]::value;};
int ID2(){return CollideDispatcher::InnerID2[b]::value;};
};
class C:public Base
{
public:
int ID1(){return CollideDispatcher::InnerID1<C>::value;};
int ID2(){return CollideDispatcher::InnerID2<C>::value;};
};
class D:public B
{
public:
int ID1(){return CollideDispatcher::InnerID1<D>::value;};
int ID2(){return CollideDispatcher::InnerID2<D>::value;};
};
void Collide(Base* c1,Base* c2)
{
CollideDispatcher::GetDisp(c1->ID1(),c2->ID2())(c1,c2);
}
int main(void)
{
Base base;A a;B b;C c;D d;
Base* p1=&c;Base* p2=&d;Base* p3=&a;
try
{
Collide(p1,p2);
Collide(p1,p3);
}
catch(std::runtime_error e)
{
std::cerr<<e.what();
}
} 这里面的collide是非对称得。
TypeList可用Append。
那个dispatcher的静态量也可以不用声明(再把Dispatch2包一次)。
c1和c2碰撞,总是先遍历c2的继承层次。
欢迎大家批评指正。 |