前言

上一篇文章讲了 iterator_traits 的编程技法,非常棒适度弥补了 C++ 语言的不足。 STL 只对迭代器加以规范,制定了 iterator_traits 这样的东西。 CGI 把这种技法进一步扩大到迭代器以外的世界,于是有了 __type_traits。双划线前缀词意指只是 CGI STL 内部所有的东西,不在 STL 标准规范之内。

__type_traits 定义和作用

在源码中 __type_traits 在 type_traits.h 文件定义,以下是泛化版本:

  1. struct __true_type {
  2. };
  3.  
  4. struct __false_type {
  5. };
  6.  
  7. //泛化版本
  8. template <class type>
  9. struct __type_traits {
  10. typedef __true_type this_dummy_member_must_be_first;
  11.  
  12. typedef __false_type has_trivial_default_constructor;
  13. typedef __false_type has_trivial_copy_constructor;
  14. typedef __false_type has_trivial_assignment_operator;
  15. typedef __false_type has_trivial_destructor;
  16. typedef __false_type is_POD_type;
  17. };

iterator_traits 负责萃取迭代器的特性,__type_traits 则负责萃取型别特性。这个特性主要是指:has_trivial_default_constructor,has_trivial_copy_constructor,has_trivial_assignment_operator,has_trivial_destructor,is_POD_type 这五种,表示是否有不重要的构造、析构、拷贝和赋值等操作,是真假属性。如果答案是肯定的,我们对这个型别进行相应操作时就可以采用更有效的措施,不调用 constructor 和 destructor 等,而采用内存直接处理操作如 malloc()、memcpy() 等等,获得最高效率。例如 int, float. double, char 等普通类型这些属性为真,不需要调用类型自身的构造和析构等。而 string 类或内嵌型别的类这些属性则是默认为假,需要调用自身的构造和析构等。这里的解释和侯捷《STL源码剖析》讲的不一样,侯捷引入 non-trivial defalt ctor 这种学术性的名称,可能这样更加专业,但我觉得不能直观表现源码,但意思是一样的,如果有问题欢迎留言讨论。

__true_type 和 __false_type 没有任何成员,不会带来额外负担,却又能标示真假。用 bool 也能达到目的,但是 bool 变量不能达到编译期绑定。CGI 把所有内嵌型别都定义为 __false_type,即定义出最保守的值。源码也针对普通类型设计特化版本,具体如下:

  1. __STL_TEMPLATE_NULL struct __type_traits<char> {
  2. typedef __true_type has_trivial_default_constructor;
  3. typedef __true_type has_trivial_copy_constructor;
  4. typedef __true_type has_trivial_assignment_operator;
  5. typedef __true_type has_trivial_destructor;
  6. typedef __true_type is_POD_type;
  7. };
  8.  
  9. __STL_TEMPLATE_NULL struct __type_traits<signed char> {
  10. typedef __true_type has_trivial_default_constructor;
  11. typedef __true_type has_trivial_copy_constructor;
  12. typedef __true_type has_trivial_assignment_operator;
  13. typedef __true_type has_trivial_destructor;
  14. typedef __true_type is_POD_type;
  15. };
  16.  
  17. __STL_TEMPLATE_NULL struct __type_traits<unsigned char> {
  18. typedef __true_type has_trivial_default_constructor;
  19. typedef __true_type has_trivial_copy_constructor;
  20. typedef __true_type has_trivial_assignment_operator;
  21. typedef __true_type has_trivial_destructor;
  22. typedef __true_type is_POD_type;
  23. };
  24.  
  25. __STL_TEMPLATE_NULL struct __type_traits<short> {
  26. typedef __true_type has_trivial_default_constructor;
  27. typedef __true_type has_trivial_copy_constructor;
  28. typedef __true_type has_trivial_assignment_operator;
  29. typedef __true_type has_trivial_destructor;
  30. typedef __true_type is_POD_type;
  31. };
  32.  
  33. __STL_TEMPLATE_NULL struct __type_traits<unsigned short> {
  34. typedef __true_type has_trivial_default_constructor;
  35. typedef __true_type has_trivial_copy_constructor;
  36. typedef __true_type has_trivial_assignment_operator;
  37. typedef __true_type has_trivial_destructor;
  38. typedef __true_type is_POD_type;
  39. };
  40.  
  41. __STL_TEMPLATE_NULL struct __type_traits<int> {
  42. typedef __true_type has_trivial_default_constructor;
  43. typedef __true_type has_trivial_copy_constructor;
  44. typedef __true_type has_trivial_assignment_operator;
  45. typedef __true_type has_trivial_destructor;
  46. typedef __true_type is_POD_type;
  47. };
  48.  
  49. __STL_TEMPLATE_NULL struct __type_traits<unsigned int> {
  50. typedef __true_type has_trivial_default_constructor;
  51. typedef __true_type has_trivial_copy_constructor;
  52. typedef __true_type has_trivial_assignment_operator;
  53. typedef __true_type has_trivial_destructor;
  54. typedef __true_type is_POD_type;
  55. };
  56.  
  57. __STL_TEMPLATE_NULL struct __type_traits<long> {
  58. typedef __true_type has_trivial_default_constructor;
  59. typedef __true_type has_trivial_copy_constructor;
  60. typedef __true_type has_trivial_assignment_operator;
  61. typedef __true_type has_trivial_destructor;
  62. typedef __true_type is_POD_type;
  63. };
  64.  
  65. __STL_TEMPLATE_NULL struct __type_traits<unsigned long> {
  66. typedef __true_type has_trivial_default_constructor;
  67. typedef __true_type has_trivial_copy_constructor;
  68. typedef __true_type has_trivial_assignment_operator;
  69. typedef __true_type has_trivial_destructor;
  70. typedef __true_type is_POD_type;
  71. };
  72.  
  73. __STL_TEMPLATE_NULL struct __type_traits<float> {
  74. typedef __true_type has_trivial_default_constructor;
  75. typedef __true_type has_trivial_copy_constructor;
  76. typedef __true_type has_trivial_assignment_operator;
  77. typedef __true_type has_trivial_destructor;
  78. typedef __true_type is_POD_type;
  79. };
  80.  
  81. __STL_TEMPLATE_NULL struct __type_traits<double> {
  82. typedef __true_type has_trivial_default_constructor;
  83. typedef __true_type has_trivial_copy_constructor;
  84. typedef __true_type has_trivial_assignment_operator;
  85. typedef __true_type has_trivial_destructor;
  86. typedef __true_type is_POD_type;
  87. };
  88.  
  89. __STL_TEMPLATE_NULL struct __type_traits<long double> {
  90. typedef __true_type has_trivial_default_constructor;
  91. typedef __true_type has_trivial_copy_constructor;
  92. typedef __true_type has_trivial_assignment_operator;
  93. typedef __true_type has_trivial_destructor;
  94. typedef __true_type is_POD_type;
  95. };
  96.  
  97. #ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
  98.  
  99. template <class T>
  100. struct __type_traits<T*> {
  101. typedef __true_type has_trivial_default_constructor;
  102. typedef __true_type has_trivial_copy_constructor;
  103. typedef __true_type has_trivial_assignment_operator;
  104. typedef __true_type has_trivial_destructor;
  105. typedef __true_type is_POD_type;
  106. };
  107.  
  108. #endif
__STL_TEMPLATE_NULL 是个宏定义,指 template<>。普通类型的特化版本这五个属性均为 __true_type。

__type_traits 应用

__type_traits 在源码中的应用很多,我这里只举 uninitialized_fill_n 这个全局函数来说明,源码定义在 stl_uninitialized.h 文件,具体如下:

  1. template<class ForwardIterator, class Size, class T>
  2. inline ForwardIterator
  3. __uninitialized_fill_n_aux(ForwardIterator first, Size n,
  4. const T& x, __true_type)
  5. {
  6. return fill_n(first, n, x); //fill_n定义下面给出
  7. }
  8.  
  9. template<class ForwardIterator, class Size, class T>
  10. ForwardIterator
  11. __uninitialized_fill_n_aux(ForwardIterator first, Size n,
  12. const T& x, __false_type)
  13. {
  14. ForwardIterator cur = first;
  15. __STL_TRY
  16. {
  17. for ( ; n > ; --n, ++cur)
  18. construct(&*cur, x); //上面分析过,__false_type需调用自身构造
  19.  
  20. return cur;
  21. }
  22.  
  23. __STL_UNWIND(destroy(first, cur));
  24. }
  25.  
  26. template<class ForwardIterator, class Size, class T, class T1>
  27. inline ForwardIterator __uninitialized_fill_n(ForwardIterator first, Size n,
  28. const T& x, T1*)
  29. {
  30. typedef typename __type_traits<T1>::is_POD_type is_POD;
  31. //根据is_POD的属性绑定不一样的函数
  32. return __uninitialized_fill_n_aux(first, n, x, is_POD());
  33.  
  34. }
  35.  
  36. template<class ForwardIterator, class Size, class T>
  37. inline ForwardIterator uninitialized_fill_n(ForwardIterator first, Size n,
  38. const T& x)
  39. {
  40. return __uninitialized_fill_n(first, n, x, value_type(first));
  41. }

上面调用的 fill_n 在 stl_glgobase.h 文件定义,调用的函数源码如下:

  1. //填充元素到半开半闭区间[first, last)
  2. template <class ForwardIterator, class T>
  3. void fill(ForwardIterator first, ForwardIterator last, const T& value) {
  4. for ( ; first != last; ++first)
  5. *first = value;
  6. }

我在程序中 debug 调试验证过,当 T 类型为普通类型 int,函数绑定的是调用 fill_n的函数,而当 T 是自定义类型,函数绑定的是含有 construct 的函数。验证了上述分析过程的正确性。

至此,我们发现,traits 真是个好东西,比 if-else 好多了,同时是在编译期绑定的,效率更高了,好神奇的技术,STL 源码值得继续学习下去!

CGI 萃取技术 __type_traits的更多相关文章

  1. C++的类型萃取技术

    应该说,迭代器就是一种智能指针,因此,它也就拥有了一般指针的所有特点——能够对其进行*和->操作.但是在遍历容器的时候,不可避免的要对遍历的容器内部有所了解,所以,设计一个迭代器也就自然而然的变 ...

  2. C++11中的技术剖析(萃取技术)

    从C++98开始萃取在泛型编程中用的特别多,最经典的莫过于STL.STL中的拷贝首先通过萃取技术识别是否是已知并且支持memcpy类型,如果是则直接通过内存拷贝提高效率,否则就通过类的重载=运算符,相 ...

  3. C++萃取技术的一个简单初探

    首先本文并不是讲解C++萃取技术,关于C++的萃取技术网上有很多文章,推荐http://www.cppblog.com/woaidongmao/archive/2008/11/09/66387.htm ...

  4. C++之萃取技术(traits)

    为什么需要类型萃取(特化) 前面我们提到了迭代器,它是一个行为类似于smart pointer之类的东西,主要用于对STL容器中的对象进行访问,而且不暴露容器中的内部结构,而迭代器所指对象的型别称为该 ...

  5. STL源代码分析--萃取编程(traits)技术的实现

    1.为什么要出现? 依照默认认定.一个模板给出了一个单一的定义,能够用于用户能够想到的不论什么模板參数!可是对于写模板的人而言,这样的方式并不灵活.特别是遇到模板參数为指针时,若想实现与类型的參量不一 ...

  6. c++11——type_traits 类型萃取

    一. c++ traits traits是c++模板编程中使用的一种技术,主要功能:     把功能相同而参数不同的函数抽象出来,通过traits将不同的参数的相同属性提取出来,在函数中利用这些用tr ...

  7. 类型萃取(type traits)

    1. 类型萃取的作用 类型萃取使用模板技术来萃取类型(包含自定义类型和内置类型)的某些特性,用以判断该类型是否含有某些特性,从而在泛型算法中来对该类型进行特殊的处理用来提高效率或者其他.例如:在STL ...

  8. 【C++】模板简述(五):类型萃取

    功能 类型萃取,在STL中用到的比较多,用于判断一个变量是否为POD类型. 简述来说可以用来判断出某个变量是内置类型还是自定义类型. 通过类型萃取,萃取到变量类型,对不同变量进行不同处理,可以提升程序 ...

  9. STL 萃取(Traits)机制剖析

    模板特化 在将萃取机制之前,先要说明模板特化 当有两个模板类,一个是通用泛型模板,一个是特殊类型模板,如果创建一个特殊类型的对象,会优先调用特殊的类型模板类,例如: template <type ...

随机推荐

  1. EMS命令

    Tibco EMS 初级使用方法小结 http://blog.csdn.net/bincavin/article/details/8290905

  2. 洛谷 P1706 全排列

    可能是最简单的题了……讲真搜索hhh 洛谷 P1706 全排列问题 题目描述 输出自然数1到n所有不重复的排列,即n的全排列,要求所产生的任一数字序列中不允许出现重复的数字. 输入输出格式 输入格式: ...

  3. oracle数据库体系结构

    一.oracle数据库体系结构 基本组成: Oracle server:一般情况下是一个instance和一个database组成 一般:1个instance只能对应一个数据库. 特殊:1个数据库可以 ...

  4. AVL平衡树(非指针实现)

    看了网上三四篇博客,学习了AVL树维护平衡的方式.但感觉他们给出的代码都有一点瑕疵或者遗漏,懂得了思想之后,花了一些时间把他们几篇的长处结合起来,没有使用指针,实现了一下.每个小逻辑功能都抽象成了函数 ...

  5. Python之python简介

    一.Python的优缺点 优点: 1.Python的定位是“优雅”.“明确”.“简单”,所以Python程序看上去总是简单易懂,初学者学Python,不但入门容易,而且将来深入下去,可以编写那些非常非 ...

  6. dcokee 安装 nginx

    1,docker pull openresty/openresty 2, mkdir  /opt/local/openresty  等等文件夹 3, docker run  --name=" ...

  7. LNMP和LAMP的搭建

    LNMP 环境:阿里云ubuntu 16 mysql: apt-get install mysql-server mysql-client php: apt-get install php-fpm p ...

  8. shell脚本编程数组

    数组: 变量:存储单个元素的内存空间 数组:存储多个元素的连续的内存空间,相当于多个变量的集合 数组名和索引 索引:编号从0开始,属于数值索引 注意:索引可支持使用自定义的格式,而不仅是数值格式,即为 ...

  9. Echarts4+EchartsGL 3D迁徙图(附源码)

    最近遇到些Echarts迁徙图问题,在实现二维地图的迁徙图后开始开发3D迁徙图,在网上一查,发现3D版本迁徙图资料较少,自己研究并借鉴一些资料后写了一个小demo,希望能帮大家少走些弯路,共同学习. ...

  10. Qt 串口通信 高速发送出错的解决方法总结

    使用网上的qextserialport-1.2类,自行开发多线程串口通信.开发的过程中,出现两个问题:   问题1:我用信号槽跨线程调用串口类MyCom 发送和接收数据,中间运行的时候,会内存错误,Q ...