Loki的泛化模式编程可真是很神奇,其中最重要的一个技术是类型链表。连boost的tuple都是模仿其编写的,可见其技术水平有多高了。Loki的TypeList的设计理念主要有两点
1.模板的偏特化技术,我前一篇文章中有所说明。
2.模板的迭代。
一、模板的偏特化技术使其可以在迭代一定次数之后迭代截止,保证其不会一直循环下去。到某一个层次便终止。下面我们就来分析一下TypeList的神奇,看看Andrei是如何把模板玩的那么出神入化。
class NullType{};
template<class T, class U>
struct TypeList
{
typedef T Head;
typedef U Tail;
};
TypeList的定义非常简单,模板类型一个是Head,一个是Tail,而Tail就类似链表的尾部NULL指针,但是这里并不是空指针,而是NullType。而Tail也是TypeList的集合。这样一步步展开就类似成了一个链表,见如下写法:
typedef TypeList<int, TypeList<double, TypeList<char>, TypeList<unsigned int, NullType>>>> IntDoubleCharUnIntType;
int double char unsiged int 这四个类就形成了一个链表,并且以NullType结尾。
二、列表的操作
1.计算链表的长度
学过数据结构链表的应该都知道,链表的长度是根据遍历链表到NULL为止来计算长度的。这里也是一样的,我们也可以用类似的方法来实现。但这里是以迭代的形式来实现的
<1>声明Length模板类,这里声明是有原因的,一个是给下面两个特化做声明。另一个是保证在使用的过程中模板参数只能是NullType或则TypeList类型
template <class> struct Length;
<2>使用NullType来特化Length模板类
template<>
Length<NullType>
{
enum {value = 0,}; //Length的长度
};
<3>使用TypeList来特化,要说明的是之前这个地方我也是一直没有想明白,为什么Length只有一个模板参数但是这里在定义Length的时候template <class T, class U>却给出了两个,是不是这个不是Length模板类的特化,这里其实只是为了说明在特化的时候用得是TypeList这个类型来进行特化,而TypeList在特化的时候需要输入两个参数而已。
所以这里咱们就可以使用递归的方法了。见如下代码。
template<class T, class U>
Length<TypeList<T, U>>
{
enum {value = 1 + Length<U>::value,};
}
这里因为U类型展开之后仍然是一个类型链表TypeList,所以可以继续往下递归,直至到NullType截止。这样就可以计算出链表的长度了,神奇吧!!!
而且前面的Length声明给后面做了一个隐含的限定,也就是在使用Length模板类的时候,只能是TypeList和NullType,因为只有这两种类型实现了Length的特化,如果传入别的类型例如Length<int>::value 等之类的是编译不过去的因为Length特化int的版本是没有实现的,只有一个Length的声明而已。可见这种编程大家在设计时候的巧妙以及独到了,真的是很厉害啊!!!!!!佩服!!!!!!
TypeList的其他类似vector数据结构的操作,例如indexOf,Append, Erase等都有通过类似的方法来实现,原理都是声明一个操作函数类,然后通过两个特化类来实现,一个实现递归操作,一个实现截止操作。剩下的请看如下代码,这里就不细致的讲解了。在这里和大家分享了。每天都进步一小步,时间长了就是一大步了。
template <class T, class U>
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<T1, T2, ...>::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<T1, TailResult> Result;
};
template<>
struct MakeTypelist<>
{
typedef NullType Result;
};
// class template Length
// Computes the length of a typelist
// Invocation (TList is a typelist):
// Length<TList>::value
// returns a compile-time constant containing the length of TList, not counting
// the end terminator (which by convention is NullType)
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 };
};
// 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<TList, index>::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 <class TList, unsigned int index> struct TypeAt;
template <class Head, class Tail>
struct TypeAt<Typelist<Head, Tail>, 0>
{
typedef Head Result;
};
template <class Head, class Tail, unsigned int i>
struct TypeAt<Typelist<Head, Tail>, i>
{
typedef typename TypeAt<Tail, i - 1>::Result Result;
};
// class template TypeAtNonStrict
// Finds the type at a given index in a typelist
// Invocations (TList is a typelist and index is a compile-time integral
// constant):
// a) TypeAt<TList, index>::Result
// returns the type in position 'index' in TList, or NullType if index is
// out-of-bounds
// b) TypeAt<TList, index, D>::Result
// returns the type in position 'index' in TList, or D if index is out-of-bounds
template <class TList, unsigned int index,
typename DefaultType = NullType>
struct TypeAtNonStrict
{
typedef DefaultType Result;
};
template <class Head, class Tail, typename DefaultType>
struct TypeAtNonStrict<Typelist<Head, Tail>, 0, DefaultType>
{
typedef Head Result;
};
template <class Head, class Tail, unsigned int i, typename DefaultType>
struct TypeAtNonStrict<Typelist<Head, Tail>, i, DefaultType>
{
typedef typename
TypeAtNonStrict<Tail, i - 1, DefaultType>::Result Result;
};
// class template IndexOf
// Finds the index of a type in a typelist
// Invocation (TList is a typelist and T is a type):
// IndexOf<TList, T>::value
// returns the position of T in TList, or NullType if T is not found in 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 { temp = IndexOf<Tail, T>::value };
public:
enum { value = (temp == -1 ? -1 : 1 + temp) };
};
// class template Append
// Appends a type or a typelist to another
// Invocation (TList is a typelist and T is either a type or a typelist):
// Append<TList, T>::Result
// returns a typelist that is TList followed by T and NullType-terminated
template <class TList, class T> struct Append;
template <> struct Append<NullType, NullType>
{
typedef NullType Result;
};
template <class T> struct Append<NullType, T>
{
typedef Typelist<T,NullType> Result;
};
template <class Head, class Tail>
struct Append<NullType, Typelist<Head, Tail> >
{
typedef Typelist<Head, Tail> Result;
};
template <class Head, class Tail, class T>
struct Append<Typelist<Head, Tail>, T>
{
typedef Typelist<Head,
typename Append<Tail, T>::Result>
Result;
};
// class template Erase
// Erases the first occurence, if any, of a type in a typelist
// Invocation (TList is a typelist and T is a type):
// Erase<TList, T>::Result
// returns a typelist that is TList without the first occurence of T
template <class TList, class T> struct Erase;
template <class T> // Specialization 1
struct Erase<NullType, T>
{
typedef NullType Result;
};
template <class T, class Tail> // Specialization 2
struct Erase<Typelist<T, Tail>, T>
{
typedef Tail Result;
};
template <class Head, class Tail, class T> // Specialization 3
struct Erase<Typelist<Head, Tail>, T>
{
typedef Typelist<Head,
typename Erase<Tail, T>::Result>
Result;
};
// class template EraseAll
// Erases all first occurences, if any, of a type in a typelist
// Invocation (TList is a typelist and T is a type):
// EraseAll<TList, T>::Result
// returns a typelist that is TList without any occurence of T
template <class TList, class T> struct EraseAll;
template <class T>
struct EraseAll<NullType, T>
{
typedef NullType Result;
};
template <class T, class Tail>
struct EraseAll<Typelist<T, Tail>, T>
{
// Go all the way down the list removing the type
typedef typename EraseAll<Tail, T>::Result Result;
};
template <class Head, class Tail, class T>
struct EraseAll<Typelist<Head, Tail>, T>
{
// Go all the way down the list removing the type
typedef Typelist<Head,
typename EraseAll<Tail, T>::Result>
Result;
};
// class template NoDuplicates
// Removes all duplicate types in a typelist
// Invocation (TList is a typelist):
// NoDuplicates<TList, T>::Result
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;
};
// class template Replace
// Replaces the first occurence of a type in a typelist, with another type
// Invocation (TList is a typelist, T, U are types):
// Replace<TList, T, U>::Result
// returns a typelist in which the first occurence of T is replaced with 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;
};
// class template ReplaceAll
// Replaces all occurences of a type in a typelist, with another type
// Invocation (TList is a typelist, T, U are types):
// Replace<TList, T, U>::Result
// returns a typelist in which all occurences of T is replaced with U
template <class TList, class T, class U> struct ReplaceAll;
template <class T, class U>
struct ReplaceAll<NullType, T, U>
{
typedef NullType Result;
};
template <class T, class Tail, class U>
struct ReplaceAll<Typelist<T, Tail>, T, U>
{
typedef Typelist<U, typename ReplaceAll<Tail, T, U>::Result> Result;
};
template <class Head, class Tail, class T, class U>
struct ReplaceAll<Typelist<Head, Tail>, T, U>
{
typedef Typelist<Head,
typename ReplaceAll<Tail, T, U>::Result>
Result;
};
// class template Reverse
// Reverses a typelist
// Invocation (TList is a typelist):
// Reverse<TList>::Result
// returns a typelist that is TList reversed
template <class TList> struct Reverse;
template <>
struct Reverse<NullType>
{
typedef NullType Result;
};
template <class Head, class Tail>
struct Reverse< Typelist<Head, Tail> >
{
typedef typename Append<
typename Reverse<Tail>::Result, Head>::Result Result;
};
// class template MostDerived
// Finds the type in a typelist that is the most derived from a given type
// Invocation (TList is a typelist, T is a type):
// MostDerived<TList, T>::Result
// returns the type in TList that's the most derived from 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 Candidate;
public:
typedef typename Select<
SuperSubclass<Candidate,Head>::value,
Head, Candidate>::Result Result;
};
// class template DerivedToFront
// Arranges the types in a typelist so that the most derived types appear first
// Invocation (TList is a typelist):
// DerivedToFront<TList>::Result
// returns the reordered TList
template <class TList> 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
TheMostDerived;
typedef typename Replace<Tail,
TheMostDerived, Head>::Result Temp;
typedef typename DerivedToFront<Temp>::Result L;
public:
typedef Typelist<TheMostDerived, L> Result;
};
} // namespace TL