[C++模板技术] TypeList(1)

来源:互联网 发布:od软件下载 编辑:程序博客网 时间:2024/05/29 08:43

C++模板编程实质上就是针对类型的编程,因此我们需要在编译期拥用对类型进行管理的方法,于是我们就引入了TypeList技法。

TypeList的原型很简单:

template <typename T,typename U>struct TypeList{using Head = T;using Tail = U;};
我们只需要维护一个Head和一个Tail类型即可以完成无限长的TypeList扩充,这种扩充是线性的,方法如下:

using CharList = TypeList<char, TypeList<unsigned char, signed char>>;using IntegerList = TypeList<char, TypeList<short, TypeList<int, TypeList<long,long long>>>>;int main(){CharList::Head x;  // char xCharList::Tail::Head y; // unsigned char yCharList::Tail::Tail z; // signed char zcout << "OK" << endl;return 0;}
以上就是构造线性TypeList的全部了,但在实际的应用中,我们需要对这种线性结构采取各种操作,就像是链表一样,为了能够对长度未知的链表进行各种操作,就必须要在链表的尾端加一个标志节点,这样的节点在C++中往往是以nullptr的形式出现的,在其他语言中,则可能是None或者null等类型。

在TypeList中,我们也需要采用这样的标志方式,其实作方法也很简单:

struct NullType{};using CharList = TypeList<char, TypeList<unsigned char, TypeList<signed char,NullType>>>;using IntegerList = TypeList<char, TypeList<short, TypeList<int, TypeList<long,TypeList<long long,NullType>>>>>;
需要注意的是,TypeList线性链的最后一个类型永远是NullType。
这就是我们所需要的TypeList原型了!接下来,我们需要为TypeList提供各种操作。

最初步的,我们需要知道一个TypeList的长度是多少,因为我们已经有NullType作为标志了,因此可以这样实现:

template <typename T>struct Length;template <>struct Length<NullType>{enum{value = 0};};template <typename T,typename U>struct Length<TypeList<T,U> >{enum{value = 1 + Length<U>::value};};
其中,第一个模板是一切的母版,这为我们之后的特化提供了基础,因为Length是针对于TypeList的,因此这里并没有给出模板类的定义,这样一来,如果Length被应用于非TypeList类型时,编译器就会报错,这样的行为也正是我们所想要的。

第二个模板特化用于针对NullType标志节点,一个NullType的长度默认为0。

第三个模板特化则用于处理一般的TypeList,可以看到,实际上求Length的过程完全是一个递归的过程。

有了Length这个工具,我们就可以很好的求出任意TypeList的长度了:

using CharList = TypeList<char, TypeList<unsigned char, TypeList<signed char,NullType>>>;using IntegerList = TypeList<char, TypeList<short, TypeList<int, TypeList<long,TypeList<long long,NullType>>>>>;int main(){cout << Length<CharList>::value << endl; // 3cout << Length<IntegerList>::value << endl; // 5return 0;}
需要注意的是,这样的线性递归在正常的程序中实际上是应该被尽量避免的,因为当链长很长时这种O(n)的递归就会有堆栈溢出的风险,而且性能会较差。然而,针对于TypeList来讲,这样的求Length操作实际上全部都发生在C++的编译期,也就是说,其在程序运行中的实际时间消耗与空间消耗是0。其次,TypeList的实际长度往往不会很大,以至于我们可以暂时不用担心堆栈溢出的问题。但是无论如何,这样的递归过程必然会导致C++编译时间的增长,这是难以避免的,但毕竟“一次编译,终身受益”,我们对于这样的消耗也是可以接受的。



原创粉丝点击