[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++编译时间的增长,这是难以避免的,但毕竟“一次编译,终身受益”,我们对于这样的消耗也是可以接受的。
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++编译时间的增长,这是难以避免的,但毕竟“一次编译,终身受益”,我们对于这样的消耗也是可以接受的。
相关文章推荐
- 将任意类型映射到一个唯一整数(C++模板实现TypeList)
- C++ 模板特化以及Typelist的相关理解
- c++ template笔记(3)非类型模板参数nontype template parameters
- 我的C++实践(8):表达式模板技术
- C++模板技术在共享内存中的应用
- 从零开始学C++之模板(三):缺省模板参数(借助标准模板容器实现Stack模板)、成员模板、关键字typename
- Java的List模板类型与C++的list模板类型的比较
- C++ 模板技术
- C++ 使用模板实现的一个List
- 使用C++模板技术实现类的动态注册和获取
- STL运用的C++技术(3)——模板实参推断
- 快速排序,c++ 模板技术表述,完全兼容标准库!!!
- 从零开始学C++之模板(三):缺省模板参数(借助标准模板容器实现Stack模板)、成员模板、关键字typename
- Loki的TypeList技术解析
- 【c++模板】模拟实现有模板的双向链表(List)(声明和定义分离)
- STL运用的C++技术(3)——模板实参推断
- STL运用的C++技术(1)——成员模板
- C++模板之SFINAE技术
- STL运用的C++技术(1)——成员模板
- list类的C++模板实现