今天就可以把STL库中迭代器的实现,和类型萃取好好整理一下了

迭代器的设计思维是STL的关键所在,在STL的实际运用和泛型思维,迭代器都扮演着十分重要的角色,STL力求把数据容器和算法的概念分开来,于是就有了STL的两大部分,容器(container)和泛型算法(algorithms),泛型算法有很多参数都是迭代器。

举一个栗子!泛型算法find()的实现!

 template<class InputIterator, class T>
InputIterator find(InputIterator first, InputIterator last , const T& value)
{
while(*first != *last && *first != value)
{
++first;
}
return first;
}

接受两个输入迭代器的参数

  • STL把迭代器分为5个类别

    • trivial迭代器(Trivial Iterator):只是一个概念,用以区分所有迭代器的定义
    • 输入迭代器(Input iterator):提供只读操作,可读取其指向元素的值,但不可以改变该元素的值(还包括trivial迭代器中的所有操作(可能是用继承?))
    • 输出迭代器(Output Iterator):提供只写操作,可改变
    • 前进迭代器(Forward Iterator):可以改变所指向元素的值,但不可以读取
    • 双向迭代器(Bidirectional Iterator):可以双向移动
    • 随机访问迭代器(Random Iterator):韩乾各种指针算数能力,可以像访问顺序表一样随机访问

之前发布的智能指针也算是迭代器的一种,原生的指针当然也可以说是迭代器,只是这么说有些狭隘了迭代器的定义,因为自定义类型的指针功能不够完善,需要重载一些运算符之类的,为什么智能指针也不能直接用作迭代器呢?因为无法获得智能指针所指向的类型!

为什么这么说?因为有的时候我们可能想要使用智能指针所指向的类型去创建一些变量,不好弄,即使是使用type_id也只是获得名字,并不能用来创建变量,有种方法可以用的

 template<class T,class U>

 void Fun_impl(T t ,U u)

 {

                  U tmp;//we got the type

 }
template<class T> void Fun(T t) { return Fun_impl(t ,*t); }

这么做就可以获得所指向的类型(并且创建了想要的变量)了,但是当我们需要一个这样的返回值的时候应该怎么办嘛,也许还是上面这种方法?看似是那么的完美,但是编译之后就无情的击碎了你的希望,编译是不通过的

但是我们可以通过内嵌型别声明来获取他们的类型(通过typeid是不行的,因为typeid只能获得类型的名称,并不能用这个名称来声明变量)

这种方法显然是可以的,但是有个隐晦的陷阱,因为不是所有传过来的都是迭代器,万一传过来的就是一个原生指针,原生指针就没有内嵌类型(当然没有,你认为一个int*内部会有内嵌类型么,话说int*有什么内部么)!!!!这就要用到偏特化的知识

那什么是偏特化呢?使用模板的时候,模版参数设定为多个template<class T, class U>模板是可以特定的

 template<class T, class U>
class class1
{
T a;
U b;
};
template<class T>
class class1<int>
{
T a;
U b;
};

上述代码中对U进行了特化,嗯!简单易懂,如果T也特化一下,就是全特化了,偏特化就是没有全都特化!

但是还有一个问题,当传过来的的指针是一种指向常值的指针(pointers to const)const int *ptr的时候,,我们很显然获得的类型就是const int,这有些不对劲,因为我们得到的类型拿来声明临时变量是没有办法使用的,就因为他指向了常值,很简单,再拿取偏特化一下就可以了(就是在上图中<T*>处改成<const T*>)

traits就扮演了一个类型萃取机的角色,用来萃取出迭代器所指向的类型(类型萃取?!)

为什么要有这么多的迭代器呢?你看容器人手一个!因为迭代器中有operator++的实现,每个容器存储的方式也不尽相同,vector是顺序存储,list是链式存储,operator++内部实现肯定不一样的,但是又想泛型编程,继承咯,封装咯。。。

  • 最常使用到的迭代器的相应类别有5种:value_type,difference_type,pointer,reference,iterator_category
    • value_type就是迭代器所指向的对象的型别,每个迭代器都应该定义有自己的value_type内嵌型别
    • difference_type用来表示两个迭代器之间的距离,因此也可以表示一个容器的最大容量
    • referecne引用?左值,因为有需要const iterator的情况出现,这时候需要一个不能改变所指向对象的迭代器在C++中,函数如果要传回左值,都是以by reference的方式进行
    • pointer_type就是简单的迭代器所指向对象的地址,就是图中第二个
    • iterator_category就是之前用的那个类型萃取,萃取出迭代器的名称,作为函数参数,激活函数重载机制,就是利用traits实现的

那么我接下来就讲讲iterator_category的相关吧

iterator_category干啥的?对下图中五种迭代器进行分类标识

这张图中的箭头并不是代表继承关系,而是概念强化关系,就是说下层一定是个上层,但上层绝不是个下层,就跟正方形是矩形的一种特殊一样,但是矩形就不是正方形

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

这是五种空壳结构体,没其他用处就是用来标识迭代器类型,用来激活函数重载机制(因为泛型算法中要求的参数都会只给最上层的类型,这样调用时,下层迭代器来了也接受)

为什么会有继承?泛型算法是支持上层迭代器作为参数传入底层迭代器的形参的!就是在这里用的,因为迭代器本身没有继承,所以用标识名继承来激活重载机制

例如advance(iterator ,n)泛型函数,它的作用是将传过来的迭代器往后走n个,每种迭代器的实现肯定不一样的,像是forward_iterator只能一个一个走,走n次,bidirectional_iterator也一样,random_access_iterator就可以一下走n个,如果写成一个,肯定会影响random_access_iterator的效率,所以分开写,那么我怎么知道改调用哪个函数呢?因为我想泛型编程(就是我懒,我想省事)肯定就想只写一个函数名,传个参数,让程序帮我选择调用哪个函数(我的天!这不就是函数重载么),但是程序需要知道我传的参数是哪种类型的迭代器(就是类型萃取呢!!!)把类型从迭代器中萃取出来!(没弄全,其他的类似)

参数列表中最后一个就是刚才建立的那五个空壳结构体!!调用_advance的时候最后一个参数给迭代器的iterator_category就行了,对!没错就这么用!让程序自己判断用哪个函数!!

具体实现:调用

 template <class InputIterator ,class Distance>
inline void advance(InputIterator& i,Distance n)
{
_advance(i, n, iterator_traits<InputIterator>::iterator_category());
}
 template<class I>
struct iterator_traits
{
    ...... 
typedef typename I::iterator_category iterator_category;
};

STL的迭代器和类型萃取的更多相关文章

  1. C++的类型萃取技术

    应该说,迭代器就是一种智能指针,因此,它也就拥有了一般指针的所有特点——能够对其进行*和->操作.但是在遍历容器的时候,不可避免的要对遍历的容器内部有所了解,所以,设计一个迭代器也就自然而然的变 ...

  2. 类型萃取(type traits)

    1. 类型萃取的作用 类型萃取使用模板技术来萃取类型(包含自定义类型和内置类型)的某些特性,用以判断该类型是否含有某些特性,从而在泛型算法中来对该类型进行特殊的处理用来提高效率或者其他.例如:在STL ...

  3. C++类型萃取

    stl中的迭代器和C++中的类型萃取: http://www.itnose.net/detail/6487058.html 赐教!

  4. 【C++】模板简述(五):类型萃取

    功能 类型萃取,在STL中用到的比较多,用于判断一个变量是否为POD类型. 简述来说可以用来判断出某个变量是内置类型还是自定义类型. 通过类型萃取,萃取到变量类型,对不同变量进行不同处理,可以提升程序 ...

  5. 头一回发博客,来分享个有关C++类型萃取的编写技巧

    废话不多说,上来贴代码最实在,哈哈! 以下代码量有点多,不过这都是在下一手一手敲出来的,小巧好用,把以下代码复制出来,放到相应的hpp文件即可,VS,GCC下均能编译通过 #include<io ...

  6. 第17课 类型萃取(1)_基本的type_traits

    1. type_traits类型萃取 (1)type_traits通过定义一些结构体或类,并利用模板类特化和偏特化的能力,给类型赋予一些特性,这些特性根据类型的不同而异.在程序设计中可以使用这些tra ...

  7. c++11——type_traits 类型萃取

    一. c++ traits traits是c++模板编程中使用的一种技术,主要功能:     把功能相同而参数不同的函数抽象出来,通过traits将不同的参数的相同属性提取出来,在函数中利用这些用tr ...

  8. 侯捷C++ Type traits(类型萃取

    泛型編程編出來的代碼,適用於任何「吻合某種條件限制」的資料型別.這已成為撰寫可復用代碼時的一個重要選擇.然而,總有一些時候,泛型不夠好 — 有時候是因為不同的型別差距過大,難以產生一致的泛化實作版本. ...

  9. 第19课 类型萃取(3)_类型选择的traits

    1. std::conditional (1)原型:template <bool Cond, class T, class F> struct conditional; //根据条件获取T ...

随机推荐

  1. 转:python中对list去重的多种方法

    对一个list中的新闻id进行去重,去重之后要保证顺序不变. 直观方法 最简单的思路就是: ids = [1,2,3,3,4,2,3,4,5,6,1] news_ids = [] for id in ...

  2. EntityFrameWork 使用时碰到的小问题

    EntityFrameWork 使用时碰到的小问题 1,在使用orm访问数据库的相目里,也要引用EntityFrameWork.dll,否则无法使用orm 否则,编译错误 错误 5 "Sys ...

  3. strcpy 和 strcat

    strcpy 原型:char *strcpy( char *dest, char *src )  头文件:#include <string.h> 功能:将src地址开始且含有NULL结束符 ...

  4. 详解收发不畅原因及U-Mail邮件中继解决之道

    邮件在商务往来中扮演着信息交流的重要角色,假如传输受阻,必将造成沟通不畅:可能三五封邮件的投递你意识不到其重要性,但假如长期需和客户保持沟 通,则需要保证其一贯的稳定性,这就很考验相关软件平台的性能是 ...

  5. DIOCP之编写第一个应用程序(二)

    构建client界面: 构建界面要比写代码更难爱,不是专业UI设计太丑,先有个界面,好写代码,客户端代码与界面设计思想:界面与数据之间分离处理,不能要接收数据的地方写代码,不然以后修改程序会死人的.

  6. oracle 模糊查询中的转义字符用法

    drop view aaa; create view aaa as select '_BCDE' A FROM DUAL UNION ALL SELECT 'ABCDE' FROM DUAL UNIO ...

  7. Myeclipse2016部署tomcat服务(别的服务类似)配置环境

    1.在工具MyEclipse的项目管理菜单中,右单机找Properties或者快捷键alt+enter,(或者直接搜索Runtimes)myEclipse/Targeted Runtimes 2.ne ...

  8. git代理设置方法解决

    git config --global https.proxy http://127.0.0.1:1080 git config --global https.proxy https://127.0. ...

  9. sizeof(结构体) = ?

    关于结构体大小怎样计算的文章,我想网上一搜到处都有人总结,本人之所以在此基础上还要发表这样的文章是想用最简单的计算方法来总结前人给出的结论,以致我们在以后在对结构体相关编程中不会陷入字节对齐的陷阱中. ...

  10. iOS手机功能汇总

    开发中经常会调用手机功能,今天来汇总一下,若有不足欢迎大家指出,下面分别介绍如下功能 : 电话 短信 邮件 通讯录 定位 跳转应用 跳转App Store 打开其他文件 电话 调用电话有下图两种不同样 ...