Modern C++ Design 笔记 第三章 3. TypeList

 套用一个现在很流行的句式,(好多什么编程之美或者代码之美的)。我想看了第三章Modern C++ Design能感受的就是递归之美。而其中主要介绍的TypeList就是这样一个递归演绎的完美的例子。

其实TypeList本身的定义非常简单。就是一个有Head有Tail的一个简单的空的定义
template
struct Typelist
{
typedef T Head;
typedef U Tail;
};
但是如果加上一下这一组宏定义,这个原来的定义就可以无限延伸了

#define LOKI_TYPELIST_1(T1) ::Loki::Typelist
#define LOKI_TYPELIST_2(T1, T2) ::Loki::Typelist
#define LOKI_TYPELIST_3(T1, T2, T3) ::Loki::Typelist

当 然这里的Loki就是本书主要介绍的Loki Library.的名字空间。用过这样的递归的调用你就可以创建出类似的LOKI_TYPELIST_50甚至LOKI_TYPELIST_100。当让 可以让他变的更为强大,强大到随意的添加一个新的类,删除其中的一个类,或者删除冗余的重复。
我们从简单的来看先:

template struct Length;
template <> struct Length
{
enum { value = 0 };
};

template
struct Length<> >
{
enum { value = 1 + Length::value };
};

这 里的实现处处投射出递归的思想,Length这样的模板如何显示出value呢。如果TList是NullType的时候(NullType是这里定义的 一个表示空的类,前面章已有说明),那长度就是0,慢慢来, 如果这个TypeList是TypeList,可以看到value = 1 + Length::value,也就是1。 当然如果是LOKI_TYPELIST_x定义的类就返回LOKI_TYPELIST_(x-1)的长度加上1。这样的实现通过反复的去头操作实现。(就 是去掉TypeList中的T来实现)这样的操作后面还有非常多。

template struct TypeAt;

template
struct TypeAt, 0>
{
typedef Head Result;
};

template
struct TypeAt, i>
{
typedef typename TypeAt::Result Result;
};

TypeAt 这个模板用来提取出这个TypeList中某个Index对应的类,非常直观。类似的如果index是0,就返回当前这个TypeList的Head,就 是第一个类对应的类型。如果是非0的i呢?就和第一个定义一样,去掉Head以后,再找整个TypeList中从Tail第一项开始的第i-1个。递归, 还是递归。这样的定义随处可见。真很佩服Andrei Alexandrescu。天才,真是天才!随着看这本书的深入,越来越觉得自己的苍白,好像从来没有学会C++过。
继续来看写稍微复杂点的定义。

template struct IndexOf;

template
struct IndexOf
{
enum { value = -1 };
};

template
struct IndexOf, T>
{
enum { value = 0 };
};

template
struct IndexOf, T>
{
private:
enum { temp = IndexOf::value };
public:
enum { value = (temp == -1 ? -1 : 1 + temp) };
};

这 个定义乍一看还真有点迷糊, 不过仔细分析看看就明了了。慢慢分析,如果这个TypeList是空的话,那就返回-1,表示不包含这个T, 如果第一个就是T的话,那就返回0这样的index。这样的流程也符合一般的写递归的流程,先找到收敛条件,然后在逐次递归:) 如果第一个是Head,还不是T那怎么办呢,我们这个value就是取决与temp,而temp的取得呢是靠从Tail开始的这个list中的 value,如果在IndexOf中没有找到T,那value就是一个是-1,那TypeList的value也就是-1,因为没有。如果能找到那之前的 value至少是0开始的,就可以依次往上加1。现在看还挺清楚的了。
就是这样的一段段的定义可以定义出这么一大陀的东西:
template struct Length;
template struct TypeAt;
template struct IndexOf;
template struct Append;
template struct Erase;
template struct EraseAll;
template struct NoDuplicates;
template struct Replace;
template struct ReplaceAll;
template struct Reverse;
template struct MostDerived;
template struct DerivedToFront;

可是有了这些个定义有什么用呢??这是一个Good Question。这样的模式可以帮助我们毫不费力的创建出一些列的满足特定需求的类

template class Unit>
class GenScatterHierarchy;
// GenScatterHierarchy specialization: Typelist to Unit
template class Unit>
class GenScatterHierarchy , Unit>
: public GenScatterHierarchy
, public GenScatterHierarchy
{
public:
typedef Typelist TList;
typedef GenScatterHierarchy LeftBase;
typedef GenScatterHierarchy RightBase;
};
// Pass an atomic type (non-typelist) to Unit
template class Unit>
class GenScatterHierarchy : public Unit
{
typedef Unit LeftBase;
};
// Do nothing for NullType
template class Unit>
class GenScatterHierarchy
{
};

template
struct Holder
{
T value_;
};
typedef GenScatterHierarchy WidgetInfo;
就像书中给出的这个例子一样。GenScatterHierarchy的定义结合了TypeList的优势,一个简单的一定WidgetInfo就定义出了至少这些个类: Holder ,Holder 和Holder 而且还有一定的继承关系, 显然他们WidgetInfo继承自他们。
所以这样的语句就很自然了
WidgetInfo obj;
string name = (static_cast &>(obj)).value_;
神奇吧。更厉害的是可以把GenScatterHierarchy这个分散的(scattered)继承关系变为线性的。那就是GenLinearHierarchy了,这个就不具体讲了,相信以后具体介绍Loki里面容器设计的时候还会设计到的。今天就到这里吧。

你可能感兴趣的:(Modern C++ Design 笔记 第三章 3. TypeList)