首先介绍C++标准程序库中的五种迭代器,关于这个可以看我的另一个笔记:http://blog.csdn.net/m0_37316917/article/details/70053513

对于这五种分类,C++标准程序库分别提供专属的标志结构加以确认:

struct input_iterator_tag{};
struct output_iterator_tag{};
struct forward_iterator_tag{}:public input_iterator_tag{};
struct bidirectional_tag:public forward_iterator_tag{};
struct random_access_iterator_tag:public bidirectional_iterator_tag{};

这些struct之间的继承关系是有效的is-a的挂系,所有forward迭代器都是input迭代器,以此类推。

traits并不是C++关键字或者一个预先定义好的构件,它们是一种技术,也是C++程序员共同遵守的协议,这个技术的要求之一是,它对内置类型和用户自定义类型的表现必须一样好,比如下面的advance函数:

template<typename IterT,typename DistT>
void advance(IterT&iter,Dist d)
{
if(iter is a random access iterator)
{
iter+=d;
}
else
{
if(d>=0)
{while(d--)++iter;}
else
{while(d++)--iter;}
}
}

advance()如果收到的实参是一个指针(例如const char*)和一个int,上述advance仍然必须有效运作,那意味着traits技术也必须能够施行于内置类型比如指针身上。

“traits必须能够施行与内置类型”意味着“类型内的嵌套信息(nesting information)”这种东西出局了,因为我们无法将信息嵌套于原始指针中国,因此类型的traits信息必须位于类型自身之外,标准技术是将它放进一个template及其一个或者多个特化版本中,这样的templates在标准程序库中有多个,其中针对迭代器者被命名为iterator_traits:

template<typename IterT>
struct iterator_traits;//迭代器分类的相关信息

如你所限,iterator_traits是个struct,西瓜上traits纵使被实现为struct,但它们却又被成为traits classes。

iterator_traits的运作方式是,针对每一个类型IterT,在struct iterator_traits内一定声明某个typedef名为iterator_category,这个typedef用来确认IterT的迭代器分类。

为了支持内置类型指针迭代器。Iterator_traits特别针对指针类型提供一个偏特化版本,由于指针的行为和random access迭代器累死,所以iterator_traits为指针指定的迭代器类型是:

template<typename IterT>
struct iterator_traits<IterT*>
{
typedef random_access_iterator_tag iterator_category;
};

现在我们可以对advance实践之前的伪代码。

template<typename IterT,typename DistT>
void advance(IterT&iter,DIstT d){
if(typeid(typename std::iterator_traits<IterT>::iterator_category)==typeif(std::random_access_iterator_tag))
......;//do something
}

但是这种方法将会导致编译问题,IterT的类型在编译期间获得,所以iterator_traits::iterator::category也可在编译期间确定,但if语句是在运行期才会核定,为什么将可在编译期完成的事情延迟到运行期才完成呢?这不仅浪费实践,也造成可执行代码的膨胀。

我们需要一个办法在编译期期间核定类型成功,这个办法就是重载:

template<typename IterT,typename DistT>
void doadvance(IterT&iter,DIstT d,std::random_access_iterator_tag)//用于实现random access迭代器
{
iter+=d;
} template<typename IterT,typename DistT>
void doadvance(IterT&iter,DIstT d,std::bidirectional_iterator_tag)//用于实现bidirectional迭代器
{
if(d>=0) {while(d--) ++iter;}
else{while(d++)--iter;}
} template<typename IterT,typename DistT>
void doadvance(IterT&iter,DIstT d,std::input_iterator_tag)//用于实现input迭代器
{
if(d<0)
throw std::out_of_range("Nagetive distance"); while(d--)++iter;
}

由于forward_iterator_tag继承自input_iterator_tag,所以上述doadvance的input_iterator_tag版本也能够处理forward迭代器,这是iterator_tag structs继承关系带来的一项红利,实际上这也是public继承带来的部分好处:针对base class编写的代码用于derived class也行得通。

有了这些doadvance重载版本,advance需要做的只是调用它们并且额外传递一个对象,后者必须带有适当的迭代器分类,于是编译期运用重载解析几只调用适当的实现代码:

template<typename IterT,typename DistT>
void advance(IterT&iter,DistT d)
{
doadvance(iter,d,typename std::iterator_traits<IterT>::iterator_category());
}

《Effective C++》再次探索traits技法的更多相关文章

  1. C++中的Traits技法

    Traits广泛应用于标准程序库.Traits classes使得"类型相关信息"在编译期可用. 认真读完下面的示例,你应该就懂了Traits技法,其实并不难. #include ...

  2. C++ traits技法的一点理解

    为了更好的理解traits技法.我们一步一步的深入.先从实际写代码的过程中我们遇到诸如下面伪码说起. template< typename T,typename B> void (T a, ...

  3. 带你深入理解STL之迭代器和Traits技法

    在开始讲迭代器之前,先列举几个例子,由浅入深的来理解一下为什么要设计迭代器. //对于int类的求和函数 int sum(int *a , int n) { int sum = 0 ; for (in ...

  4. STL源代码剖析(二) - 迭代器与traits技法

    提要 先看一段用迭代器的代码: int a[] = {1, 2, 3, 4, 5}; vector<int> v1( a, a+5); vector<int>::iterato ...

  5. 仿SGI STL的traits技法

    首先是iterator traits,这个是用来萃取迭代器的特性的 #ifndef _STL_ITERATOR_H_ #define _STL_ITERATOR_H_ #include <cst ...

  6. Traits技法

    扮演"特性萃取机"角色,萃取各个迭代器的特性(迭代器的相应类型) 模板特例化:提供一份template定义式,而其本身仍为templatization 通过class templa ...

  7. STL源码--iterator和traits编程技法

    第一部分 iterator学习 STL iterators定义: 提供一种方法,使之能够依序巡访某个聚合物(容器)所含的各个元素,而又无需暴露该聚合物的内部表达方式. 任何iteartor都应该提供5 ...

  8. [转载]《STL源码剖析》阅读笔记之 迭代器及traits编程技法

    本文从三方面总结迭代器   迭代器的思想   迭代器相应型别及traits思想   __type_traits思想 一 迭代器思想 迭代器的主要思想源于迭代器模式,其定义如下:提供一种方法,使之能够依 ...

  9. 对C++ templates类模板的几点补充(Traits类模板特化)

    前一篇文章<浅谈C++ templates 函数模板.类模板以及非类型模板参数>简单的介绍了什么是函数模板(这个最简单),类模板以及非类型模板参数.本文对类模板再做几点补充. 文章目录1. ...

  10. STL内存管理

    1. 概述 STL Allocator是STL的内存管理器,也是最低调的部分之一,你可能使用了3年stl,但却不知其为何物. STL标准如下介绍Allocator the STL includes s ...

随机推荐

  1. Java 集合简介 一

    什么是集合? 集合就是由若干个确定的元素所构成的整体.例如,5只小兔构成的集合: 在数学中,我们经常遇到集合的概念.例如: ● 有限集合 ○ 一个班所有的同学构成的集合: ○ 一个网站所有的商品构成的 ...

  2. 【算法训练营day7】LeetCode454. 四数相加II LeetCode383. 赎金信 LeetCode15. 三数之和 LeetCode18. 四数之和

    [算法训练营day7]LeetCode454. 四数相加II LeetCode383. 赎金信 LeetCode15. 三数之和 LeetCode18. 四数之和 LeetCode454. 四数相加I ...

  3. NVIDIA Isaac Gym安装与使用

    NVIDIA做的Isaac Gym,个人理解就是一个类似于openai的Gym,不过把环境的模拟这个部分扔到了GPU上进行,这样可以提升RL训练的速度. 官网:https://developer.nv ...

  4. 前端框架Vue------>第二天学习(1)插槽

    欢迎加入刚建立的社区:http://t.csdn.cn/Q52km 加入社区的好处: 1.专栏更加明确.便于学习 2.覆盖的知识点更多.便于发散学习 3.大家共同学习进步 3.不定时的发现金红包(不多 ...

  5. 一、docker的介绍

    一.虚拟化和容器 虚拟化介绍 操作系统层虚拟化是指通过划分一个宿主操作系统的特定部分,产生一个个隔离的操作执行环境.操作系统层的虚拟化是操作系统内核直接提供的虚拟化,虚拟出的操作系统之间共享底层宿主操 ...

  6. 京东云开发者|ElasticSearch降本增效常见的方法

    Elasticsearch在db_ranking 的排名又(双叒叕)上升了一位,如图1-1所示;由此可见es在存储领域已经蔚然成风且占有非常重要的地位. 随着Elasticsearch越来越受欢迎,企 ...

  7. QQ登录

    public function login(){ $urlencode = urlencode("http://www.zhangxuhui.com/index/Index/callback ...

  8. Go语言核心36讲50

    作为拾遗的部分,今天我们来讲讲与Go程序性能分析有关的基础知识. Go语言为程序开发者们提供了丰富的性能分析API,和非常好用的标准工具.这些API主要存在于: runtime/pprof: net/ ...

  9. C温故补缺(二):volatile

    volatile 参考:CSDN volatile也是一个类型修饰符,被其修饰的变量意味着可以被某些编译器未知的因素修改,如操作系统,硬件,线程等. 当遇到volatile修饰的变量时,编译器对访问该 ...

  10. MySQL数据库:6、约束的概述及语法

    Python基础之MySQL数据库 目录 Python基础之MySQL数据库 一.约束概述 1.为什么要约束 2.什么是约束 3.约束的分类 4.查看当前表已有的约束 二.约束语法及用法 1.无符号 ...