• SGI STL类型萃取: __type_traits


    __type_traits基本概念

    iterator_traits是STL针对迭代器加以规范,用来萃取迭代器特性的机制。SGI STL把这种技法扩大到迭代器以外的地方,于是有了__type_traits。(双下划线表示是内部所用,不在STL标准规范内)

    iterator_traits 提供机制,用于萃取迭代器的5个特性:iterator_category(迭代器类型)、value_type(所指对象类型)、difference_type(迭代器做算术运算类型)、pointer(指针类型)、reference(引用类型)。

    SGI中,__type_traits位于<type_traits.h>,它提供了一种机制,用于萃取不同类型属性:在编译期就能完成函数派生决定(function dispatch)。这对于编写template很有帮助,比如,当我们准备对一个“元素类型未知”的数组执行copy操作时,如果能事先知道元素类型是否有一个trivial copy constructor(平凡的拷贝构造函数),就能帮助我们决定是否使用更高效的memcpy()或memmove()。

    __type_traits内嵌类型

    程序中,可以这样应用__type_traits,T代表任意类型:

    __type_traits<T>::has_trivial_default_constructor
    __type_traits<T>::has_trivial_copy_constructor
    __type_traits<T>::has_trivial_assignment_operator
    __type_traits<T>::has_trivial_destructor
    __type_traits<T>::is_POD_type // POD: Plain Old Data
    

    上面的式子,返回的是“真”或“假”,便于我们决定采用上面策略,但结果不是bool值,而是有着真/假属性的“对象”,因为我们希望编译器可以在编译期,就利用响应结果来进行参数推导,而编译器只有面对class object形式的参数,才会做参数类型推导。因此,上面式子应该传回这样的东西:

    // 用作真、假的标记类
    struct __true_type {};
    struct __false_type {};
    

    这两个空白的class没有任何成员,仅作为标记类,不会带来任何负担。

    为了达成上面5个式子,在__type_traits内定义一些typedefs,其(返回)值不是__true_type,就是__false_type。下面是SGI的做法:

    template<class type>
    struct __type_traits
    {
      typedef __true_type this_dummy_member_must_be_first;
      /* 不要移除这个成员,它通知“有能力自动将__type_traits特化的编译器说,
      我们现在看到的这个__type_traits template是特殊的。这是为了确保万一编译器也使用一个名为__type_traits而其实与此处定义无任何关联的template时,所有事情仍将顺利运作”*/
    
      /* 以下条件应该遵守,因为编译器有可能自动为各类型专属的__type_traits特化版本:
        - 你可以重新安排以下的成员次序
        - 你可以移除以下任何成员
        - 绝对不可以将以下成员重命名而没有改变编译器中对应名称
        - 新加入的成员会被视为一般成员,除非你在编译期中加上适当支持
       */
      typedef __false_type has_trivial_default_constructor;
      typedef __false_type has_trivail_copy_constructor;
      typedef __false_type has_trivail_assignment_constructor;
      typedef __false_type has_trivail_destructor;
      typedef __false_type is_POD_type; // POD: Plain Old Data
    };
    

    为什么SGI把所有__type_traits的内嵌类型都定义为__false_type?
    因为SGI定义出最保守的值,然后,再针对每个标量类型(scalar types)设计适当的__type_traits特化版本。

    __type_traits可以接受任何类型的参数,5个typedefs将经由以下管道获得实值:

    • 一般具现(general instantiation),内含对所有类型都必定有效的保守值。比如,上面各个has_trivial_xxx类型都被定义为__false_type,就是对所有类型都有效的保守值。
    • 经过声明的特化版本,例如<type_traits.h>中对所有C++标量类型(scalar types)(指bool/char/int/float/double等基本类型)都提供了对应特化声明。
    • 某些编译器自动为所有类型提供适当的特化版本。

    __type_traits针对C++标量类型的特化版

    /* 以下针对C++基本型别char, signed char, unsignedchar, short, unsigned short,
    int, unsigned int, long, unsigned long, float, double, long double 提供特化版本.
    注意, 每个成员的值都是__true_type, 表示这些型别都可采用最快速方式(如memcpy)来进行拷贝(copy)或赋值(assign) */
    
    #   define __STL_TEMPLATE_NULL template<>
    
    __STL_TEMPLATE_NULL struct __type_traits<bool> {
       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_NO_BOOL */
    
    __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;
    };
    
    ...
    

    __type_traits在STL中的应用

    __type_traits在SGI STL中应用很广泛,举几个例子,前面这篇文章也提到过SGI STL内存基本处理工具:uninitialized_copy/uninitialized_fill/uninitialized_fill_n
    ,也有POD类型介绍。本文只挑选跟__type_traits有关的重点讲。

    uniitialized_fill_n()全局函数

    // __type_traits应用: uninitialized_fill_n()
    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));
    }
    

    uninitialized_fill_n()函数以x为初始化元素,自迭代器first开始构造n个元素。为求取最大效率,首先用value_type()萃取出迭代器first的value type,再用__type_traits 判断该型别是否为POD类型:

    // __type_traits萃取T的is_POD_type特性,判断是否为POD类型
    // 利用__type_traits判断该型别是否为POD类型
    template<class ForwardIterator, class Size, class T, class T1>
    inline ForwardIterator __uninitialized_fiil_n(ForwardIterator first, Size n, const  T& x, T1*) {
           typedef typename __type_traits<T1>::is_POD_type is_POD;
           return __uninitialized_fiil_n_aux(first, n, x, is_POD);
    }
    

    下面就“是否为POD类型”采取最适当的措施:

    // 如果不是POD类型, 就派送(dispatch)到这里
    template<class ForwardIterator, class Size, class T>
    ForwardIterator __uninitialized_fill_n_aux(ForwardIterator first, Size n, const T&  x, __false_type) {
      ...
    }
    
    // 如果是POD类型, 就会派送(dispatch)到这里.
    template<class ForwardIterator, class Size, class T>
    inline ForwardIterator ___uninitialized_fill_n_aux_(ForwardIterator first, Size n,  const T& x, __true_type) {
      ...
    }
    
    // 以下定义于<stl_algobase.h>中的fill_n()
    template<class OutputIterator, class Size, class T>
    OutputIterator fill_n(OutputIterator first, Size n, const T& value) {
      ...
    }
    

    负责对象析构的destroy()全局函数

    // destroy()第一个版本, 接受一个指针
    template<class T>
    inline void destroy(T* pointer) {
      ...
    }
    
    // destroy()第二个版本, 接受两个迭代器. 次函数设法找出元素的数值类型,
    // 进而利用__type_traits<>求取最适当措施
    template<class ForwardIterator>
    inline void destroy(ForwardIterator first, ForwardIterator last) {
      __destroy(first, last, value_type(first));
    }
    
    // __type_traits 萃取T的has_trivial_destructor特性, 判断是否为平凡析构函数
    // 判断元素的数值类型(value type)是否有trivial destructor
    template<class ForwardIterator, class T>
    inline void __destroy(ForwardIterator first, ForwardIterator last, T*) {
      typedef typename __type_traits<T>::has_trivial_destructor  trivial_destructor;
      __destroy_aux(first, last, trivial_destructor());
    }
    
    // 如果元素的数值类型(value type)有non-trivial destructor, 则派送(dispatch)到这里
    template<class ForwardIterator>
    inline void __destroy_aux(ForwardIterator first, ForwardIterator last,  __false_type) {
      ...
    }
    
    // 如果元素的数值类型(value type)有trivial destructor, 则派送(dispatch)到这里
    template<class ForwardIterator>
    inline void __destroy_aux(ForwardIterator first, ForwardIterator last,  __true_type) {
    }
    

    copy()全局函数

    copy()全局函数用于拷贝。

    // 利用__type_traits萃取T的has_trivial_copy_constructor特性,判断是否为平凡copy构造函数
    // 拷贝一个数组, 其元素为任意型别, 视情况采用最有效率的拷贝手段
    template<class T> inline void copy(T* source, T* destination, int n) {
           copy(source, destination, n, typename  __type_traits<T>::has_trivial_copy_constructor());
    }
    
    // 拷贝一个数组, 其元素型别拥有non-trivial copy constructors, 则dispatch到这里
    template<class T> void copy(T* source, T* destination, int n, __false_type) {
           // ...
    }
    
    // 拷贝一个数组, 其元素型别拥有trivial copy constructors, 则dispatch到这里
    // 可借助memcpy()完成工作
    template<class T> void copy(T* source, T* destination, int n, __true_type) {
           // ...
    }
    

    自定义__type_traits特化版

    通常,不应该直接使用__type_traits,STL内部使用。正如SGI <type_traits.h>内部有这样的声明:

    /* NOTE: This is an internal header file, included by other STL headers.
     * You should not attempt to use it directly.
     */
    

    因为,编译器通常会自动为class生成这些特性,这些特性取决于自定义class是否包含trivial default constructor,trivial copy constructor,trivial assignment operator,或者trivial destructor。但有些古老的编译器,可能并不能为class生成这些特性,导致即使是POD类型,但萃取出来的特性依然是__false_type。此时,需要自行设计一个__type_traits特化版本,明确告诉编译器该class具有哪些特性:

    // 假设自定义class名为Shape
    // 针对Shape设计的__type_traits特化版本
    template<> struct __type_traits<Shape> {
        typedef __true_type  has_trivial_default_constructor; // 告诉编译器Shape拥有trivial default constructor
        typedef __false_type has_trivial_copy_constructor;
        typedef __false_type has_trivial_assignment_constructor;
        typedef __false_type has_trivial_destructor;
        typedef __false_type is_POD_type;
    };
    

    如何判断一个class什么时候有自己的non-trivial default constructor,non-trivial copy constructor,non-trivial assignment operator,non-trivial destructor?
    一个简单判断原则:如果class内含指针成员,并且进行了动态内存配置,那么该class就需要实现出自己的non-trivial-xxx。

  • 相关阅读:
    微信公众平台订阅号和服务号和企业号的区别
    微信支付现金红包接口说明及应用实例代码
    Android开发环境配置
    在自己的android工程中使用actionbarsherlock以及slidingmenu
    android个推推送平台的使用
    android网络
    android String 类型转换成UTF-8格式
    【转】android神一样的模拟器——genymotion
    基于百度云推送的实时通信客户端实现(三)
    基于百度云推送的实时通信客户端实现(二)
  • 原文地址:https://www.cnblogs.com/fortunely/p/16226017.html
Copyright © 2020-2023  润新知