• CGI 萃取技术 __type_traits


    前言

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

    __type_traits 定义和作用

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

    struct __true_type {
    };
    
    struct __false_type {
    };
    
    //泛化版本
    template <class type>
    struct __type_traits { 
       typedef __true_type     this_dummy_member_must_be_first;
       
       typedef __false_type    has_trivial_default_constructor;
       typedef __false_type    has_trivial_copy_constructor;
       typedef __false_type    has_trivial_assignment_operator;
       typedef __false_type    has_trivial_destructor;
       typedef __false_type    is_POD_type;
    };

    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,即定义出最保守的值。源码也针对普通类型设计特化版本,具体如下:

    __STL_TEMPLATE_NULL struct __type_traits<char> {
       typedef __true_type    has_trivial_default_constructor;
       typedef __true_type    has_trivial_copy_constructor;
       typedef __true_type    has_trivial_assignment_operator;
       typedef __true_type    has_trivial_destructor;
       typedef __true_type    is_POD_type;
    };
    
    __STL_TEMPLATE_NULL struct __type_traits<signed char> {
       typedef __true_type    has_trivial_default_constructor;
       typedef __true_type    has_trivial_copy_constructor;
       typedef __true_type    has_trivial_assignment_operator;
       typedef __true_type    has_trivial_destructor;
       typedef __true_type    is_POD_type;
    };
    
    __STL_TEMPLATE_NULL struct __type_traits<unsigned char> {
       typedef __true_type    has_trivial_default_constructor;
       typedef __true_type    has_trivial_copy_constructor;
       typedef __true_type    has_trivial_assignment_operator;
       typedef __true_type    has_trivial_destructor;
       typedef __true_type    is_POD_type;
    };
    
    __STL_TEMPLATE_NULL struct __type_traits<short> {
       typedef __true_type    has_trivial_default_constructor;
       typedef __true_type    has_trivial_copy_constructor;
       typedef __true_type    has_trivial_assignment_operator;
       typedef __true_type    has_trivial_destructor;
       typedef __true_type    is_POD_type;
    };
    
    __STL_TEMPLATE_NULL struct __type_traits<unsigned short> {
       typedef __true_type    has_trivial_default_constructor;
       typedef __true_type    has_trivial_copy_constructor;
       typedef __true_type    has_trivial_assignment_operator;
       typedef __true_type    has_trivial_destructor;
       typedef __true_type    is_POD_type;
    };
    
    __STL_TEMPLATE_NULL struct __type_traits<int> {
       typedef __true_type    has_trivial_default_constructor;
       typedef __true_type    has_trivial_copy_constructor;
       typedef __true_type    has_trivial_assignment_operator;
       typedef __true_type    has_trivial_destructor;
       typedef __true_type    is_POD_type;
    };
    
    __STL_TEMPLATE_NULL struct __type_traits<unsigned int> {
       typedef __true_type    has_trivial_default_constructor;
       typedef __true_type    has_trivial_copy_constructor;
       typedef __true_type    has_trivial_assignment_operator;
       typedef __true_type    has_trivial_destructor;
       typedef __true_type    is_POD_type;
    };
    
    __STL_TEMPLATE_NULL struct __type_traits<long> {
       typedef __true_type    has_trivial_default_constructor;
       typedef __true_type    has_trivial_copy_constructor;
       typedef __true_type    has_trivial_assignment_operator;
       typedef __true_type    has_trivial_destructor;
       typedef __true_type    is_POD_type;
    };
    
    __STL_TEMPLATE_NULL struct __type_traits<unsigned long> {
       typedef __true_type    has_trivial_default_constructor;
       typedef __true_type    has_trivial_copy_constructor;
       typedef __true_type    has_trivial_assignment_operator;
       typedef __true_type    has_trivial_destructor;
       typedef __true_type    is_POD_type;
    };
    
    __STL_TEMPLATE_NULL struct __type_traits<float> {
       typedef __true_type    has_trivial_default_constructor;
       typedef __true_type    has_trivial_copy_constructor;
       typedef __true_type    has_trivial_assignment_operator;
       typedef __true_type    has_trivial_destructor;
       typedef __true_type    is_POD_type;
    };
    
    __STL_TEMPLATE_NULL struct __type_traits<double> {
       typedef __true_type    has_trivial_default_constructor;
       typedef __true_type    has_trivial_copy_constructor;
       typedef __true_type    has_trivial_assignment_operator;
       typedef __true_type    has_trivial_destructor;
       typedef __true_type    is_POD_type;
    };
    
    __STL_TEMPLATE_NULL struct __type_traits<long double> {
       typedef __true_type    has_trivial_default_constructor;
       typedef __true_type    has_trivial_copy_constructor;
       typedef __true_type    has_trivial_assignment_operator;
       typedef __true_type    has_trivial_destructor;
       typedef __true_type    is_POD_type;
    };
    
    #ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
    
    template <class T>
    struct __type_traits<T*> {
       typedef __true_type    has_trivial_default_constructor;
       typedef __true_type    has_trivial_copy_constructor;
       typedef __true_type    has_trivial_assignment_operator;
       typedef __true_type    has_trivial_destructor;
       typedef __true_type    is_POD_type;
    };
    
    #endif
    __STL_TEMPLATE_NULL 是个宏定义,指 template<>。普通类型的特化版本这五个属性均为 __true_type。

    __type_traits 应用

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

    template<class ForwardIterator, class Size, class T>
    inline ForwardIterator
    __uninitialized_fill_n_aux(ForwardIterator first, Size n,
                               const T& x, __true_type) 
    {
      return fill_n(first, n, x); //fill_n定义下面给出
    }
    
    template<class ForwardIterator, class Size, class T>
    ForwardIterator
    __uninitialized_fill_n_aux(ForwardIterator first, Size n,
                               const T& x, __false_type) 
    {
      ForwardIterator cur = first;
      __STL_TRY 
      {
        for ( ; n > 0; --n, ++cur)
          construct(&*cur, x);  //上面分析过,__false_type需调用自身构造
        
        return cur;
      }
      
      __STL_UNWIND(destroy(first, cur));
    }
    
    template<class ForwardIterator, class Size, class T, class T1>
    inline ForwardIterator __uninitialized_fill_n(ForwardIterator first, Size n,
                                                  const T& x, T1*) 
    {
      typedef typename __type_traits<T1>::is_POD_type is_POD;
      //根据is_POD的属性绑定不一样的函数
      return __uninitialized_fill_n_aux(first, n, x, is_POD());
                                        
    }
    
    template<class ForwardIterator, class Size, class T>
    inline ForwardIterator uninitialized_fill_n(ForwardIterator first, Size n,
                                                const T& x) 
    {
      return __uninitialized_fill_n(first, n, x, value_type(first));
    }

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

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

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

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

  • 相关阅读:
    [TimLinux] CSS 纯CSS实现动画展开/收起功能
    [TimLinux] CSS pre超长自动换行
    j2ee之struts2表单细节处理
    j2ee之struts2的国际化数据方式
    j2ee之struts2拦截器()
    j2ee之struts2文件下载
    j2ee之struts2文件上传
    j2ee国际化数据方式
    j2ee监听器的实现及配置方法
    j2ee过滤器实现的主要代码
  • 原文地址:https://www.cnblogs.com/evenleee/p/11658183.html
Copyright © 2020-2023  润新知