如果一个迭代器要兼容stl,必须遵循约定,自行以内嵌型别定义的方式定义出相应型别。根据书中介绍,最常用到的迭代器型别有五种:value type,difference type, pointer, reference, iterator catagoly,如果你希望你开发的容器能与stl水乳交融,一定要为你的容器的迭代器定义这五种相应型别。

迭代器相应型别之一:value type

  所谓value type 是指迭代器所指对象的型别。任何一个打算与stl算法有完美搭配的class, 都应该定义自己的value type内嵌型别。

迭代器型别之二:difference type

  difference type用来表示两个迭代器之间的距离的类型,例如容器的容量,比如stl 的count()函数,其返回值就是迭代器的difference type:

template <class I, class T>
typename iterator_traits<I>::difference_type count(I first, I last, const T& value)
{
typedef typename iterator_traits<I>::difference_type n = ;
for (;first != last; ++first)
if (*first == value)
++n;
return n;
}

针对相应型别difference type, 原生指针使用哪个类型呢?表示空间大小一般使用unsigned int,stl为原生指针定义的特化版本为:

//带内嵌类型的迭代器
template <class I>
struct iterator_traits
{
typedef typename I::difference_type difference_type;
};
//原生指针
template <class I>
struct iterator_traits<I*>
{
typedef ptrdiff_t difference_type;
};
//const 原生指针
template <class I>
struct iterator_traits<const I*>
{
typedef ptrdiff_t difference_type;
};

这样的话当我们任何时候需要使用迭代器的difference type,可以这么写:

typename iterator_traits<I>::difference_type

迭代器型别之三:reference type

在c++中,函数如果要传回左值,都是以by reference 的方式进行,所以如果p是一个迭代器,他的value type 是T,那么*p 应该是T&(即reference type)

迭代器的解引操作operator* 返回的就是reference type,为了能融合stl,我们的迭代器也必须要定义reference 内嵌型别

stl 为reference type设计了一般版本和偏特化版:

//一般带内嵌类型的迭代器
template <class I>
struct iterator_traits
{
typedef typename::I::reference reference;
};
//原生指针
template <class I>
struct iterator_traits<I*>
{
typedef I& reference;
};
//const 原生指针
template <class I>
struct iterator_traits<const I*>
{
typedef const I& reference;
};

迭代器型别之四:pointer type

即指针类型,也就是说我们可以返回一个指针,指向迭代器所指之物,STL设计如下:

//一般带内嵌类型的迭代器
template <class I>
struct iterator_traits
{
typedef typename::I::pointer pointer;
};
//原生指针
template <class I>
struct iterator_traits<I*>
{
typedef I* pointer;
};
//const 原生指针
template <class I>
struct iterator_traits<const I*>
{
typedef const I* pointer;
};

迭代器型别之五:iterator_category

讨论前必须先知道stl迭代器的分类:

input iterator:只读迭代器(++)

output iterator:只写迭代器(++)

forward iterator:可读写迭代器(++)

bidirectional iterator:可双向移动迭代器(++,--)

random access iterator:可随机访问迭代器(+n,-n)

设计算法时,如果可能,我们应该给入参迭代器提供明确的说明,如果算法需要input iterator 我们给个random access 的当然可以,但不是最贴切的。下面列出stl算法中使用各个iterator示例:

stl中使用 input iterator示例:

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

stl使用output iterator示例:

template <class OutputIterator, class Size, class T>
void fill_n (OutputIterator first, Size n, const T& val);

stl使用forward iterator示例:

template <class ForwardIterator, class T>
void replace (ForwardIterator first, ForwardIterator last,
const T& old_value, const T& new_value);

stl使用bidirectional iterator示例:

template <class BidirectionalIterator1, class BidirectionalIterator2>
BidirectionalIterator2 move_backward (BidirectionalIterator1 first,
BidirectionalIterator1 last,
BidirectionalIterator2 result);

stl使用random access iterator示例:

template <class RandomAccessIterator>
void partial_sort (RandomAccessIterator first, RandomAccessIterator middle,
RandomAccessIterator last);

当我们在使用这些算法的时候,我们是直接使用iterator,并不明确指定自己传进去的是什么iterator

例如vector:

std::vector<int> myVector;
std::find(myVector.begin(), myVector.end(),);

这个begin和end返回的是什么类型的迭代器?

其实根据vector的数据结构我们可以推测是reandom access iterator,因为vector是连续内存结构,支持随机访问,stl对vector的begin函数返回值定义如下:

An iterator to the beginning of the sequence container.

If the vector object is const-qualified, the function returns a const_iterator. Otherwise, it returns an iterator.

Member types iterator and const_iterator are random access iterator types (pointing to an element and to a const element, respectively).

继续回到iterator_category上,假设我们要实现一个函数,入参为迭代器p和一个整形n,函数内将p累进n次,下面有三分定义:

//只读迭代器,只支持++
template <class InputIterator, class Distance>
void advance(InputIterator&p, Distance n)
{
while (n--) ++p;
} //双向迭代器,支持++、--
template <class BidirectionalIterator, class Distance>
void advance(BidirectionalIterator& p, Distance n)
{
if (n >= )
while (n--) ++p;
else
while (n++) --p;
} //随机访问迭代器,支持随机访问
template <class RandomAccessIterator, class Distance>
void advance(RandomAccessIterator& p, Distance n)
{
p += n;
}

现在当程序员要调用advance时,应该用哪个呢?如果你是一个vector,调用第二个定义,那么效率就下降了,如果我们把三个函数合并成一个,使用一个变量区分使用哪个函数,大概代码如下:

template <class InputIterator, class Distance>
void advance(InputIterator&p, Distance n, int type)
{
if (type===input)
...
else if (type==output)
...
else
...
}

这样做我们调用时还是要多传一个参数,但我们实际上并没有这样调用advance函数,stl利用重载实现:

struct input_iterator_tag{};
struct output_iterator_tag{};
struct forward_iterator_tag{};
struct bidirectional_iterator_tag{};
struct random_access_iterator_tag{};
//为了表示是内部函数,我们以__开头
//只读迭代器,只支持++
template <class InputIterator, class Distance>
void __advance(InputIterator&p, Distance n, input_iterator_tag)
{
while (n--) ++p;
} //双向迭代器,支持++、--
template <class BidirectionalIterator, class Distance>
void __advance(BidirectionalIterator& p, Distance n, bidirectional_iterator_tag)
{
if (n >= )
while (n--) ++p;
else
while (n++) --p;
} //随机访问迭代器,支持随机访问
template <class BidirectionalIterator, class Distance>
void __advance(BidirectionalIterator& p, Distance n, random_access_iterator_tag)
{
p += n;
}
//对外统一接口:(这里有个疑问:统一接口中为什么入参是InputIterator? 既然设计的初衷是接受任何类型的迭代器,就不应该指定特定类型,我们甚至可以命名成T)
template <class InputIterator, class Distance>
void advance(InputIterator& p, Distance n)
{
__advance(p, n, iterator_traits<InputIterator>::iterator_category());
}

因此,为了满足上述行为,traits还要加一个型别:

//一般带内嵌类型的迭代器
template <class I>
struct iterator_traits
{
typedef typename::I::iterator_category iterator_category;
};
//原生指针,因为我们原生指针支持随机访问,所以要定义成random access
template <class I>
struct iterator_traits<I*>
{
typedef random_access_iterator_tag iterator_category;
};
//const 原生指针
template <class I>
struct iterator_traits<const I*>
{
typedef random_access_iterator_tag iterator_category;
};

这样我们的iterator就有了五种类型,我们的traits 也要萃取迭代器的这五种类型,这样才能完全融入stl,完整代码如下:

//自定义的迭代器必须定义的五种型别
template <class Category, class T, class Distance = ptrdiff_t, class Pointer = T*, class Reference = T&>
struct iterator
{
typedef T value_type;
typedef Distance difference_type;
typedef Reference reference;
typedef Pointer pointer;
typedef Category iterator_category;
};
//把之前的五种合并在一个traits中
template <class Iterator>
struct iterator_traits
{
typedef typename Iterator::value_type value_type;
typedef typename Iterator::difference_type difference_type;
typedef typename::Iterator::reference reference;
typedef typename::Iterator::pointer pointer;
typedef typename::Iterator::iterator_category iterator_category;
};
//原生指针偏特化版
template <class Iterator>
struct iterator_traits<T*>
{
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T& reference;
typedef T* pointer;
typedef random_access_iterator_tag iterator_category;
};
//const原生指针偏特化版
template <class Iterator>
struct iterator_traits<const T*>
{
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef const T& reference;
typedef const T* pointer;
typedef random_access_iterator_tag iterator_category;
};

根据以上代码,我们可以提供一系列函数供算法使用:

//定义一个函数,获取迭代器类型
template <class Iterator>
inline typename::iterator_traits<Iterator>::iterator_category iterator_category(const Iterator&)
{
typedef typename iterator_traits<iterator>::iterator_category category;
return category();
}
//定义一个函数,获取迭代器的distance_type
template <class Iterator>
inline typename::iterator_traits<Iterator>::difference_type distance_type(const Iterator&)
{
typedef typename iterator_traits<iterator>::difference_type difference;
return difference();
} //定义一个函数,获取迭代器的value_type
template <class Iterator>
inline typename::iterator_traits<Iterator>::value_type value_type(const Iterator&)
{
typedef typename iterator_traits<iterator>::value_type value;
return value();
}
//或者返回value_type*
template <class Iterator>
inline typename::iterator_traits<Iterator>::value_type* value_type(const Iterator&)
{
typedef typename iterator_traits<iterator>::value_type* value;
return value;
}

STL迭代器之二:迭代器型别的更多相关文章

  1. C++迭代器之'插入迭代器

    1. 定义 插入型迭代器(Insert Iterator),又叫插入器(Inserter). 2. 作用 插入迭代器的主要功能为把一个赋值操作转换为把相应的值插入容器的操作.算法库对所有在容器上的操作 ...

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

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

  3. C++迭代器之'反向迭代器'

    反向迭代器(Reverse Iterator)是普通迭代器的适配器,通过重新定义自增和自减操作,以达到按反序遍历元素的目的.如果在标准算法库中用反向迭代器来代替普通的迭代器,那么运行结果与正常情况下相 ...

  4. [知识点]C++中STL容器之map

    UPDATE(20190416):写完vector和set之后,发现不少内容全部引导到map上了……于是进行了一定的描述补充与更正. 零.STL目录 1.容器之map 2.容器之vector 3.容器 ...

  5. Python之列表生成式、生成器、可迭代对象与迭代器

    本节内容 语法糖的概念 列表生成式 生成器(Generator) 可迭代对象(Iterable) 迭代器(Iterator) Iterable.Iterator与Generator之间的关系 一.语法 ...

  6. python之函数闭包、可迭代对象和迭代器

    一.函数名的应用 # 1,函数名就是函数的内存地址,而函数名()则是运行这个函数. def func(): return print(func) # 返回一个地址 # 2,函数名可以作为变量. def ...

  7. day14带参装饰器,迭代器,可迭代对象 , 迭代器对象 ,for迭代器 , 枚举对象

    复习 ''' 函数的嵌套定义:在函数内部定义另一个函数 闭包:被嵌套的函数 -- 1.外层通过形参给内层函数传参 -- 2.验证执行 开放封闭原则: 功能可以拓展,但源代码与调用方式都不可以改变 装饰 ...

  8. python函数之可迭代对象、迭代器的判断

    怎么判断一个对象是可迭代对象还是迭代器 例子 from collections import Iterable, Iterator lst = ['Today is Wednesday', 'Tomo ...

  9. python基础一 ------可迭代对象和迭代器对象

    可迭代对象和迭代器对象:前者生成后者 比喻:10个硬币都可以一一数(迭代),放入到存钱罐(可以取钱的那种),那这个存钱罐就是一个迭代器对象 需求:从网络抓取各个城市气温信息,并依次显示若依次抓取较多的 ...

随机推荐

  1. Svg path画线(不管是直线还是曲线)在一定情况下线条的宽度不一的情况(记录)

    在项目中涉及到svg: 使用path划线实现图表功能. 记录在实现的过程中发现的问题:path在小像素的情况下画出的线条宽度不一样.这是为什么呢? 以下是我做的猜想: 可以看图 在宽度给的很足的时候没 ...

  2. cPage分页,asp.net自定义分页,url传值分页,支持datalist、gridview、Repeater等

    asp.net分页是最最常用的功能,实现方式也很多,使用不同的控件有不同的分页方式. 下面分享一个我们团队内部使用了多年的一个分页控件cPage,是自己设计编写,没有冗余,简单.快速. cPage,现 ...

  3. 前端 动态表单提交(post、put)

    第一步:form表单定义统一属性 <input type="text" class="form-value" /> 第二步:获取所有值 var fo ...

  4. 优先级反转实验,使用信号量实现【RT-Thread学习笔记 5】

    RTOS中很经典的问题.就是在使用共享资源的时候,优先级低的进程在优先级高的进程之前执行的问题.这里模拟这种情况. 下面的实验模拟了优先级反转的情况: 先定义三个线程: //优先级反转实验 rt_se ...

  5. WindowsForm--Bubble User Control

    创建一个自定义用户控件,拖入一个label:lblWords,和一个richTextBox:txtWords 代码: using System; using System.Collections.Ge ...

  6. Windows服务定时执行方式

    采用System.Timers.Timer 间隔固定时间执行 方式一:间隔固定的时间执行一次,关键代码: protected override void OnStart(string[] args) ...

  7. AttributeError: 'list' object has no attribute 'write_pdf'

    我在可视化决策树,运行以下代码时报错:AttributeError: 'list' object has no attribute 'write_pdf' 我使用的是python3.4 from sk ...

  8. Emacs使用projectile-rails 插件注意事项

    插件地址 https://github.com/asok/projectile-rails 我自己使用rbenv这个ruby版本控制工具来,管理下载ruby,但是他不是全局安装ruby之类的gem,如 ...

  9. jquery mobile button样式设置

    <a href="#" class="ui-btn">提交</a> ui-btn表示按钮样式 ui-btn-a,ui-btn-b:the ...

  10. python字符串的编码格式

    参考网站: http://www.cnblogs.com/siqi/archive/2012/11/10/2763598.html 环境: win7 x64 python v2.7.10 结论: 1 ...