上节给出了iterator_traits以及用到traits机制的部分函数的完整代码,可以看到traits机制能够提取迭代器的特性从而调用不同的函数,实现效率的最大化。显然这么好的机制不应该仅局限于在STL里面使用,在前某一节中我们也有说到,traits机制能够萃取类的特性,而这个类分为两个类别,一是迭代器类,二普通类,迭代器类我们已经有所了解了,那么本节就来学习负责萃取普通类型特性的__type_traits吧。

  于普通类型而言,我们所关注的特性是指:这个类型是否具备non-trivial defalt ctor?是否具备non-trivial copy ctor?是否具备non-trivial assignment ctor?是否具备non-trivial dtor?在关注__typr_traits之前,我们很有必要来讨论一下上述的几个词组是什么意思。其中ctor为构造函数,那么copy ctor就是拷贝构造函数,assignment ctro为赋值构造函数,defalt ctor为默认构造函数。而trivial的意思为琐碎的、无意义的。那么判断这4个构造函数是否有意义的条件是:如果至少满足一下了3条中的1条,那么就是说明其类是有意义(non- trivial)的:

  1. 显式(explict)定义了这四种函数
  2. 类里有非静态非POD的数据成员
  3. 有基类

  何为POD?简单解释就是指C风格的struct结构体定义的数据结构或者C++的内建类型,POD类型必然有trivial ctor/dtor/copy/assignment四种函数。

  那么区分构造函数是否有意义又有什么意义呢?

  如果这个类都是trivial ctor/dtor/copy/assignment函数,我们对这个类进行构造、析构、拷贝和赋值时可以采用最有效率的方法,是不调用无所事事正真的那些ctor/dtor等,而是直接采用内存操作如malloc()、memcpy()等提高性能,获取最高效率。这对于大规模而操作频繁的容器,有着显著的效率提升。

  而这个__type_traits机制就能针对不同的类特性,在编译时期完成函数的调用决定。这对于template很有帮助,例如,当我们准备对一个类型特性未知的数组进行copy操作时,如果我们能事先知道其元素的类型特性是否有一个trivial copy ctor,便能够帮我们我们决定是否可使用快速的memcpy()或memmove()。

  与使用iterator_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

  我们希望通过调用这些式子来告诉我们T类型是否是有意义的(以便我们决定采取什么策略),但其结果不应该只是个bool值,应该是个有着真/假性质的“对象”,因为我们希望利用其相应结果来进行参数推导(等会给出代码例子),而编译器只有面对class object形式的参数,才会做参数推导。为此,上述式子应该传回这样的东西:

 struct __true_type {};
struct __false_type {};

  这两个空白的结构体没有任何东西,不会带来额外的负担,却又能标示真假,满足我们所需。

  为此,我们应该为上述的五个式子定义一些typedef,准确告知T是否有意义:

 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_trivial_copy_constructor;
typedef __false_type has_trivial_assignment_operator;
typedef __false_type has_trivial_destructor;
typedef __false_type is_POD_type;
// 所谓 POD 意指 Plain Old Data structure.
};

  this_dummy_member_must_be_first:因为某些编译器会提供__type_traits机制,自动会为所有类型提供适当的特化版本,所以为了将编译器内部的__type_traits和STL 自带的__type_traits区分开来,提供该特殊的定义式。

  为什么SGI把所有的内嵌类型都定义为__false_type呢?这是最保守的做法,它默认认为所有的自定义类型都是具有有意义的构造函数,至于内部基本类型,SGI STL会为其提供特化版本。总的来说,上述的__type_traits可以接受任何类型的参数,但五个typedef会经由以下的管道获得实值:

  • 自定义类型,内含对所有类型都必定有效的保守值。上述各个has_trivial_xxx型别都被定义为__false_type,就是对所有类型都必定有效的保守值。
  • 经过声明的特化版本,例如<type_traits.h>内对所有C++基本类型提供了对应的特化声明。稍后展示。
  • 某些编译器会自动为所有类型提供适当的特化版本。

  以下便是<type_traits.h>对所有C++基本类型所定义的__type_traits特化版本。这些定义对于内建有__type_traits支持能力的编译器并无伤害,对于无该支持能力的编译器而言,实属必要。

 /* 以下针对 C++ 基本型別 char, signed char, unsigned char, short, unsigned short,
int, unsigned int, long, unsigned long, float, double, long double 提供特化版本。
注意,每一个成员的值都是 __true_type,表示这些型別都可采用最快速方式(例如 memcpy)
來进行拷贝动作或赋值动作。*/ //注意,SGI STL<stl_config.h>将以下出现的 _STL_TEMPLATE_NULL
//定义为template<>,是所谓的class template explicit specialization __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;
}; #else /* __STL_CLASS_PARTIAL_SPECIALIZATION */ 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;
}; 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;
}; 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;
};

  对于__type_traits的应用,我们可以举一个之前学习Allocator时就遇到的函数destroy():

 // 以下是 destroy() 第二版本,接受兩個迭代器。此函式是設法找出元素的數值型別,
// 進而利用 __type_traits<> 求取最適當措施。
template <class ForwardIterator>
inline void destroy(ForwardIterator first, ForwardIterator last) {
__destroy(first, last, value_type(first));
} // 判斷元素的數值型別(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…
template <class ForwardIterator>
inline void
__destroy_aux(ForwardIterator first, ForwardIterator last, __false_type) {
for ( ; first < last; ++first)
destroy(&*first);
} // 如果元素的數值型別(value type)有 trivial destructor…
template <class ForwardIterator>
inline void __destroy_aux(ForwardIterator, ForwardIterator, __true_type) {}

  可以看到,在__destroy函数里,利用了__type_traits<T>机制判断T类型是否具有无意义的析构函数,然后再根据判断结果进行参数推导,调用相应的函数,如果是无意义的析构函数就不做很任何事情,提升性能;如果是有意义的析构函数,就为该区间里的所有对象逐一调用析构函数。

  正如上所言,于一切自定义类型,__type_traits<T>机制默认认为其具有有意义的构造函数(除非是使用内部提供__type_traits机制的编译器就能自动识别该类型是否有意义,但大部分编译器缺乏这种特异功能),这样的结果过于保守,那么如何让__type_traits<T>机制能够为我们的自定义类型提取到真正的特性呢?答案就是自行为自己设计的类型提供__type_traits特化版本,明白地告诉编译器事实。举例,假设我自行定义了一个shape class,是一个没有默认构造函数的类型(即存在trivial defalt ctor),那么它的__type_traits特化版本应该是:

 template<> struct __type_traits <Shade> {
typedef __true_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;
}

  究竟一个类什么时候该有自己的non-trivial defalt ctor,non-trivial copy ctor,non-trivial assignment ctor,non-trivial dtor?一个简单的判断准则就是:如果类内包含指针成员,并且对它进行内存动态配置,那么这个类就需要实现出自己的non-trivial-xxx。

STL源码剖析——Iterators与Traits编程#5 __type_traits的更多相关文章

  1. STL源码剖析——iterators与trait编程#2 Traits编程技法

    在算法中运用迭代器时,很可能用到其相应类型.什么是相应类型?迭代器所指对象的类型便是其中一个.我曾有一个错误的理解,那就是认为相应类型就是迭代器所指对象的类型,其实不然,相应类型是一个大的类别,迭代器 ...

  2. STL源码剖析——iterators与trait编程#4 iterator源码

    在前两节介绍了迭代器的五个相应类型,并讲述如何利用traits机制提取迭代器的类型,但始终是把iteartor_traits类分割开来讨论,这影响我们的理解,本节将给出iteator的部分源码,里面涵 ...

  3. STL源码剖析——iterators与trait编程#3 iterator_category

    最后一个迭代器的相应类型就是iterator_category,就是迭代器本身的类型,根据移动特性与实行的操作,迭代器被分为了五类: Input Iterator:这种迭代器所指的对象,不允许外界改变 ...

  4. STL源码剖析——iterators与trait编程#1 尝试设计一个迭代器

    STL的中心思想在于:将数据容器与算法分开,独立设计,再用一帖粘着剂将它们撮合在一起.而扮演粘着剂这个角色的就是迭代器.容器和算法泛型化,从技术角度来看并不困难,C++的模板类和模板函数可分别达成目标 ...

  5. 《STL源码剖析》----2.23 value_type()和__type_traits<>如何实现

    在2.13小节destory()第二版本接受两个迭代器找出元素类型,代码如下 其中value_type()判断出类型,__type_traits判断是否存在trivial destructor 在3. ...

  6. 《STL源码剖析》学习之traits编程

    侯捷老师在<STL源码剖析>中说到:了解traits编程技术,就像获得“芝麻开门”的口诀一样,从此得以一窥STL源码的奥秘.如此一说,其重要性就不言而喻了.      之前已经介绍过迭代器 ...

  7. 【STL 源码剖析】浅谈 STL 迭代器与 traits 编程技法

    大家好,我是小贺. 点赞再看,养成习惯 文章每周持续更新,可以微信搜索「herongwei」第一时间阅读和催更,本文 GitHub : https://github.com/rongweihe/Mor ...

  8. STL源码剖析 迭代器(iterator)概念与编程技法(三)

    1 STL迭代器原理 1.1  迭代器(iterator)是一中检查容器内元素并遍历元素的数据类型,STL设计的精髓在于,把容器(Containers)和算法(Algorithms)分开,而迭代器(i ...

  9. STL源码剖析之序列式容器

    最近由于找工作需要,准备深入学习一下STL源码,我看的是侯捷所著的<STL源码剖析>.之所以看这本书主要是由于我过去曾经接触过一些台湾人,我一直觉得台湾人非常不错(这里不涉及任何政治,仅限 ...

随机推荐

  1. LeetCode 1046. Last Stone Weight

    原题链接在这里:https://leetcode.com/problems/last-stone-weight/ 题目: We have a collection of rocks, each roc ...

  2. LeetCode 723. Candy Crush

    原题链接在这里:https://leetcode.com/problems/candy-crush/ 题目: This question is about implementing a basic e ...

  3. 54、Spark Streaming:DStream的transformation操作概览

    一. transformation操作概览 Transformation Meaning map 对传入的每个元素,返回一个新的元素 flatMap 对传入的每个元素,返回一个或多个元素 filter ...

  4. CTF RCE(远程代码执行)

    目录 php代码执行 一.相关函数 1.代码注入 2.命令执行 二.命令执行的绕过 1.命令执行的分隔符 2.空格代替 3.绕过 4.命令执行的各种符号 三.命令无回显的情况 1.判断 2.利用 四. ...

  5. mysql死锁(锁与事务)

    线上某服务时不时报出如下异常(大约一天二十多次):“Deadlock found when trying to get lock;”. Oh, My God! 是死锁问题.尽管报错不多,对性能目前看来 ...

  6. semi-join子查询优化 -- LooseScan策略

    LooseScan执行semi-join子查询的一种策略. 我们将通过示例来演示这种松散(LooseScan)策略.假设,我们正在查找拥有卫星的国家.我们可以通过以下查询获得它们(为了简单起见,我们忽 ...

  7. Buffon投针问题

  8. rabbitmq - 消息接收,解析xml格式数据时异常:ERROR not well-formed (invalid token): line 4, column 46

    ERROR alsv odoo.addons.cus_alsv.utils.alsv_about_mq.get_data_from_mq: parse_xml_data_from_mq: not we ...

  9. 推荐:使用 Anaconda 工具搭建并管理 Python 环境

    https://www.anaconda.com/distribution/#download-section  官网下载地址 https://mirror.tuna.tsinghua.edu.cn/ ...

  10. webconfig 配置 分离

    https://blog.csdn.net/zhifeiya/article/details/38828711 如标题,如何把 asp.net webconfig的appSettings分离到单独文件 ...