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。

原文链接: https://www.cnblogs.com/fortunely/p/16226017.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    SGI STL类型萃取: __type_traits

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/402608

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月21日 上午11:08
下一篇 2023年4月21日 上午11:08

相关推荐