STL笔记(7)——Traits编程技法(二)

来源:互联网 发布:淘宝手机拍照技巧集锦 编辑:程序博客网 时间:2024/06/05 09:22

STL笔记(7)——Traits编程技法(二)

迭代器型别

五种迭代器型别:

  1. value_type
  2. different_type
  3. pointer
  4. reference
  5. iterator_category

前四个比较简单,分别是:
value_type
表示迭代器所指元素的型别。
different_type
表示迭代器之间的距离的型别,在针对原生指针的特化版本用ptrdiff_t表示,即:

template<typename T>struct iterator_traits<T*>{    typedef ptrdiff_t difference_type;}

reference_type & pointer
这两种类型都返回左值。
其中reference_type表示迭代器所指的对象的左值,而pointer表示迭代器所指对象的地址的左值。
前者对应操作符* ,后者对应操作符->

最后一个比较复杂的型别:iterator_category
迭代器被分为5类:
Input :只读
Output :只写
Forward :可读写
Bidirectional:可双向读写
Random Access:可以随机访问
这些迭代器存在一种功能上的汇总关系,如图

这里写图片描述
在代码里面则是用继承来实现

在设计算法时,如果可能尽量使用最合适的版本,也就是尽量找迭代器类型的最佳匹配。

书中以advance函数为例,在stl_iterator_base.h文件中定义,为了对比STL源码的版本,书中介绍了一种低效率的方式,即在代码中对迭代器类型进行判断,然后分别调用不同的函数,这样的方法直到运行的时候采取判断,如果再要提高效率,就只有在编译期就选择正确的版本。就需要使用函数重载了。

首先定义5中迭代器型别方便重载:

//继承关系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()函数是外部接口,在内部都要加上前缀__advance(),这就是真正的函数实现,通过迭代器型别进行重载。

//1.外部使用的接口template <class _InputIterator, class _Distance>inline void advance(_InputIterator& __i, _Distance __n) {  __STL_REQUIRES(_InputIterator, _InputIterator);  __advance(__i, __n, iterator_category(__i));}//__advance的重载版本,这里只有类型,没有临时变量(因为不必要)仅仅用来重载//重载 __advance  input_iteratortemplate <class _InputIter, class _Distance>inline void __advance(_InputIter& __i, _Distance __n, input_iterator_tag) {  while (__n--) ++__i;}//BidirectionalIterator重载版本template <class _BidirectionalIterator, class _Distance>inline void __advance(_BidirectionalIterator& __i, _Distance __n,                       bidirectional_iterator_tag) {  __STL_REQUIRES(_BidirectionalIterator, _BidirectionalIterator);  if (__n >= 0)//可以双向    while (__n--) ++__i;  else    while (__n++) --__i;}//RandomAccessIterator重载版本template <class _RandomAccessIterator, class _Distance>inline void __advance(_RandomAccessIterator& __i, _Distance __n,                       random_access_iterator_tag) {  __STL_REQUIRES(_RandomAccessIterator, _RandomAccessIterator);  __i += __n;}

那么问题来了,Forward版本的__advance去哪了?
原来由于继承关系,当参数无法完全匹配时,会自动传递调用 Input的版本。

最后一个问题:STL是怎么判定迭代器型别的?也就是是如何实现iterator_category(__i)
首先先看:

template <class _Iterator>struct iterator_traits {  typedef typename _Iterator::iterator_category iterator_category;  typedef typename _Iterator::value_type        value_type;  typedef typename _Iterator::difference_type   difference_type;  typedef typename _Iterator::pointer           pointer;  typedef typename _Iterator::reference         reference;};//原生指针的特化版本template <class _Tp>struct iterator_traits<_Tp*> {  typedef random_access_iterator_tag iterator_category;  typedef _Tp                         value_type;  typedef ptrdiff_t                   difference_type;  typedef _Tp*                        pointer;  typedef _Tp&                        reference;};//const原生指针的特化版本template <class _Tp>struct iterator_traits<const _Tp*> {  typedef random_access_iterator_tag iterator_category;  typedef _Tp                         value_type;  typedef ptrdiff_t                   difference_type;  typedef const _Tp*                  pointer;  typedef const _Tp&                  reference;};

上述是iterator_traits的定义,包含了之前提到的所有5个型别,并有原生指针和const指针两个特化版本,然后,STL源码中写了如下函数:

template <class _Iter>inline typename iterator_traits<_Iter>::iterator_category//一整行作为函数返回类型__iterator_category(const _Iter&){  typedef typename iterator_traits<_Iter>::iterator_category _Category;  return _Category();//创建一个临时对象 例如int()创建一个临时的int对象。}//而我们真正使用的接口直接调用了上述函数template <class _Iter>inline typename iterator_traits<_Iter>::iterator_categoryiterator_category(const _Iter& __i) { return __iterator_category(__i); }
1 0
原创粉丝点击