Loki的TypeList技术解析(一)

2014-11-23 23:41:32 · 作者: · 浏览: 3

Loki的泛化模式编程可真是很神奇,其中最重要的一个技术是类型链表。连boost的tuple都是模仿其编写的,可见其技术水平有多高了。Loki的TypeList的设计理念主要有两点

1.模板的偏特化技术,我前一篇文章中有所说明。

2.模板的迭代。

一、模板的偏特化技术使其可以在迭代一定次数之后迭代截止,保证其不会一直循环下去。到某一个层次便终止。下面我们就来分析一下TypeList的神奇,看看Andrei是如何把模板玩的那么出神入化。

class NullType{};


template

struct TypeList

{

typedef T Head;

typedef U Tail;

};

TypeList的定义非常简单,模板类型一个是Head,一个是Tail,而Tail就类似链表的尾部NULL指针,但是这里并不是空指针,而是NullType。而Tail也是TypeList的集合。这样一步步展开就类似成了一个链表,见如下写法:

typedef TypeList , TypeList >>> IntDoubleCharUnIntType;

int double char unsiged int 这四个类就形成了一个链表,并且以NullType结尾。

二、列表的操作

1.计算链表的长度

学过数据结构链表的应该都知道,链表的长度是根据遍历链表到NULL为止来计算长度的。这里也是一样的,我们也可以用类似的方法来实现。但这里是以迭代的形式来实现的

<1>声明Length模板类,这里声明是有原因的,一个是给下面两个特化做声明。另一个是保证在使用的过程中模板参数只能是NullType或则TypeList类型

template struct Length;


<2>使用NullType来特化Length模板类

template<>

Length

{

enum {value = 0,}; //Length的长度

};


<3>使用TypeList来特化,要说明的是之前这个地方我也是一直没有想明白,为什么Length只有一个模板参数但是这里在定义Length的时候template 却给出了两个,是不是这个不是Length模板类的特化,这里其实只是为了说明在特化的时候用得是TypeList这个类型来进行特化,而TypeList在特化的时候需要输入两个参数而已。

所以这里咱们就可以使用递归的方法了。见如下代码。

template

Length >

{

enum {value = 1 + Length::value,};

}

这里因为U类型展开之后仍然是一个类型链表TypeList,所以可以继续往下递归,直至到NullType截止。这样就可以计算出链表的长度了,神奇吧!!!

而且前面的Length声明给后面做了一个隐含的限定,也就是在使用Length模板类的时候,只能是TypeList和NullType,因为只有这两种类型实现了Length的特化,如果传入别的类型例如Length ::value 等之类的是编译不过去的因为Length特化int的版本是没有实现的,只有一个Length的声明而已。可见这种编程大家在设计时候的巧妙以及独到了,真的是很厉害啊!!!!!!佩服!!!!!!

TypeList的其他类似vector数据结构的操作,例如indexOf,Append, Erase等都有通过类似的方法来实现,原理都是声明一个操作函数类,然后通过两个特化类来实现,一个实现递归操作,一个实现截止操作。剩下的请看如下代码,这里就不细致的讲解了。在这里和大家分享了。每天都进步一小步,时间长了就是一大步了。

    template 
   
    
    struct Typelist
    {
       typedef T Head;
       typedef U Tail;
    };

// Typelist utility algorithms

    namespace TL
    {

////////////////////////////////////////////////////////////////////////////////
// class template MakeTypelist
// Takes a number of arguments equal to its numeric suffix
// The arguments are type names.
// MakeTypelist
    
     ::Result // returns a typelist that is of T1, T2, ... //////////////////////////////////////////////////////////////////////////////// template < typename T1 = NullType, typename T2 = NullType, typename T3 = NullType, typename T4 = NullType, typename T5 = NullType, typename T6 = NullType, typename T7 = NullType, typename T8 = NullType, typename T9 = NullType, typename T10 = NullType, typename T11 = NullType, typename T12 = NullType, typename T13 = NullType, typename T14 = NullType, typename T15 = NullType, typename T16 = NullType, typename T17 = NullType, typename T18 = NullType > struct MakeTypelist { private: typedef typename MakeTypelist < T2 , T3 , T4 , T5 , T6 , T7 , T8 , T9 , T10, T11, T12, T13, T14, T15, T16, T17, T18 > ::Result TailResult; public: typedef Typelist
     
       Result; }; template<> struct MakeTypelist<> { typedef NullType Result; }; //////////////////////////////////////////////////////////////////////////////// // class template Length // Computes the length of a typelist // Invocation (TList is a typelist): // Length
      
       ::value // returns a compile-time constant containing the length of TList, not counting // the end terminator (which by convention is NullType) //////////////////////////////////////////////////////////////////////////////// template 
       
         struct Length; template <> struct Length
        
          { enum { value = 0 }; }; template 
         
           struct Length< Typelist
          
            > { enum { value = 1 + Length
           ::value }; }; //////////////////////////////////////////////////////////////////////////////// // class template TypeAt // Finds the type at a given index in a typelist // Invocation (TList is a typelist and index is a compile-time integral // constant): // TypeAt
            
             ::Result // returns the type in position 'index' in TList // If you pass an out-of-bounds index, the result is a compile-time error //////////////////////////////////////////////////////////////////////////////// template 
             
               stru