对于给typelist附加元素,我写的代码比较简单,但这个话题可不简单。typelist是编译阶段的链表行为类型链表,对于push_front而言,仅仅需要重新定义一个类型就可以了,但是我们这里谈的是push_back,所以其实是在NullType前进行插入元素,这里的首要问题是找到NullType的位置,找到了它就是push_front行为了。移除某个元素的时候,我们遇到同样的问题,你首先要定位,很幸运,我们有编译期的if手段,通过递归推导,我们可以漂亮的完成这个任务:
6.移除typelist中的某个元素
template < class T >
struct Erase < NullType,T >
... {
typedef NullType Result;
} ;
template 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;
} ;
在找到T-Tail段的时候,我们移除了T,是的,你也许想到了,在这个时候继续递归推导,我们可以移除typelist里所有元素。
7.移除所有元素
struct EraseAll < Typelist < T,Tail > ,T >
... {
typedef EraseAll<Tail,T> Result;
} ;
一切都那么自然,我们在之前已经考虑到了所有问题Erase和EraseAll只是一个类型的替换,但编译器为你做了很多推导。
8.移除重复元素
移除重复元素其实是对每个Head而言你对Tail调用EraseAll,这个想法很好,你也许想了解一下移除重复元素的递归思维,这也是对的,希望你的想法是先有前者后有后者,这样的思维负担要小很多。
实际中Loki使用了类这样的方法:
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;
} ;
其实单递归而言,你有多种选择,你可以从从头元素开始依次查找,也可以从尾开始查找到头,但是,找到这个问题得简单优雅的解决方式的思维过程是让人憧憬的,多思考这些你会提高很多。
你可以有多种解决问题的方法,但是请不要停止对优雅的追逐。
9.取代typelist中的某个元素
如果是取代Head,这没有任何问题,否则,你要找到T的位置,或者说就是让它变成Head,这太简单了。
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;
} ;
有了这点代码和我们一直追求的思想,取代所有类型自然不再话下。
10.为typelist局部更换次序
正如虚函数可以保证最深的继承被调用一样,对于typelist而言,你可能希望它有一定的顺序以执行某些任务,譬如双分派。如在移除重复元素时的经验,你需要递归推导,重新定义一个类型存放结果是个不错的选择,这样可以减缓思维的压力。
这里有若干问题,首先如何判断继承关系,很幸运,之前我们讨论的SUPERSUBCLASS可以解决这个问题,其次如何找到最末端的继承者,你可以一个一个的比较,是的,类型选择可以解决这个问题,让我们包装一下类型选择使之可以找到
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 Candidate;
public:
typedef typename Select<SUPERSUBCLASS(Candidate,Head),Head,Candidate>::Result Result;
} ;
如果你对前面的每个细节都很认真,那你一定会觉得这些代码很熟悉,你可以用心去思考设计深处的东西,如果你不是,那你要复习以前的东西,其实这是一个平衡,技术来不得半点虚假和造作。
如此可以用迭代的方式进行排序:
template <>
struct DerivedToFront < NullType >
... {
typedef NullType Result;
} ;
struct DerivedToFront < Typelist < Head,Tail > >
... {
private:
typedef typename MostDerived<Tail,Head>::Result TheMostDerived;
typedef typename Replace<Tail,TheMostDerived,Head>::Result L;
public:
typedef Typelist<TheMostDerived,L> Result;
} ;
事情就是这样的,选择,筛除,构造。
引用Andrei的话,你可能认为typelist很有魅力、很有趣、或者很丑陋,其实你还没有真正看到什么东西。