您的位置:首页 > 编程语言 > C语言/C++

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

2017-08-21 22:29 309 查看
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 x
CharList::Tail::Head y; // unsigned char y
CharList::Tail::Tail z; // signed char z
cout << "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; // 3
cout << Length<IntegerList>::value << endl; // 5
return 0;
}需要注意的是,这样的线性递归在正常的程序中实际上是应该被尽量避免的,因为当链长很长时这种O(n)的递归就会有堆栈溢出的风险,而且性能会较差。然而,针对于TypeList来讲,这样的求Length操作实际上全部都发生在C++的编译期,也就是说,其在程序运行中的实际时间消耗与空间消耗是0。其次,TypeList的实际长度往往不会很大,以至于我们可以暂时不用担心堆栈溢出的问题。但是无论如何,这样的递归过程必然会导致C++编译时间的增长,这是难以避免的,但毕竟“一次编译,终身受益”,我们对于这样的消耗也是可以接受的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息