今天就可以把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. OPTIMIZE TABLE 小解

    首先看一下语法:  OPTIMIZE [NO_WRITE_TO_BINLOG | LOCAL] TABLE tbl_name [, tbl_name] ... 我们知道mysql存储引擎里面的数据和索 ...

  2. Entity Framework走马观花之把握全局 (转)

    上一篇<Entity Framework技术导游系列开篇与热身 > ========================================= 在深入学习某项技术之前,应该努力形成 ...

  3. leetcode 6. ZigZag Conversion

    https://leetcode.com/problems/zigzag-conversion/ 题目: 将字符串转化成zigzag模式. 例如 "abcdefghijkmlnpq" ...

  4. Spring里PropertyPlaceholderConfigurer类的使用

    1. PropertyPlaceholderConfigurer是个bean工厂后置处理器的实现,也就是 BeanFactoryPostProcessor接口的一个实现.PropertyPlaceho ...

  5. Flash Builder常见菊紧问题集锦

    FB的错误多多,不定什么时候就让你蛋碎,路遇操蛋问题集锦如下: 1.有次用Flash Builder 4.7,打开之后马上自动关闭,试了几次都这样,解决办法如下: 到C:\Documents and ...

  6. ASP.NET之Cookie(坑爹的Response.Cookies.Remove)(转)

      在web开发中Cookie是必不可少的 .NET自然也有一个强大的Cookie操作类,我们用起来也非常方便,不过在使用中我们会发现一个坑爹的事情Response.Cookies.Remove删除不 ...

  7. google垂直搜索结果

    佰年金融 所谓“垂直”很干净地分离出来,而不是在谷歌算作有机列表的结果,但该行已开始模糊.例如,现在许多视频结果似乎是直接整合为有机(万SERP的例子).我治疗的新的“有深度的文章”作为一个垂直的结果 ...

  8. chattr无法删除某个文件

    chattr LNMP无法删除或更改权限,显示:rm: cannot remove `.user.ini': Operation not permitted 无法删除".user.ini&q ...

  9. CC1310电源管脚

    对于48pin脚的CC1310而言,属于电源类的管脚如下: 上述电源类管脚的关系如下: 1 VDDS类管脚 VDDS类管脚包括VDDS.VDDS2.VDDS3和VDDS_DCDC四个管脚.其中VDDS ...

  10. EL使用:打印集合

    <%@page import="java.util.HashMap"%><%@page import="java.util.Map"%> ...