[C++从进阶到入门] —— 迭代器的五种型别

195 阅读2分钟

本文介绍迭代器的value type,difference type,reference type,pointer type,iterator_category五种型别,阅读本文前,请确保你已经理解Traits编程技巧

value 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) {
	typename iterator_traits<I>::difference_type n = 0;
    while(first != last) {
    	if(*(first++) == value) {
        	++n;
        }
    }
}

stddef.h定义了ptrdiff_t作为原生指针的difference type,针对T*const T*设计偏特化萃取机,就可以使用typename iterator_traits<I>::difference_type萃取任何迭代器的difference type。

reference type & pointer type

reference type与pointer type分别对应引用与指针类型。

template <class I>
struct iterator_traits {
	typedef typename I::pointer pointer;
    typedef typename I::reference reference;
};

template <class I>
struct iterator_traits<T*> {
	typedef T* pointer;
    typedef T& reference;
};

template <class I>
struct iterator_traits<const T*> {
	typedef const T* pointer;
    typedef const T& reference;
};

iterator_category

迭代器可根据移动特性与施行操作分为五类:

Input Iterator:只读迭代器。

Output Iterator:只写迭代器。

Forward Iterator:单向读写迭代器。

Bidirectional Iterator:双向读写迭代器。

Random Access Iterator:类指针迭代器。

以advanced()函数为例,该函数可以让某个迭代器前进n次,对于不同的迭代器类型,其前进方式是不一样的,例如Forward Iterator通过++运算符前进,但是Random Access Iterator可以通过+=运算符前进,当时当程序调用advanced()时,调用FI版本对RAI而言效率过低,而调用RAI版本则无法接受FI,下面的代码是一种解决办法。

template <class InputIterator, class Distance>
void advanced(InputIterator& i, Distance n) {
	if(is_FI(i)) {
    	advanced_FI(i, n);
    } else if(is_RAI(i)) {
    	advanced_RAI(i, n);
    } ...
}

但是这样在是形式才确定advanced()版本,效率低,我们希望在编译器确定它,函数重载机制可以帮助我们实现这个目标,我们需要一个占位参数用于重载决议。

struct ii_tag {};
struct oi_tag {};
struct fi_tag: public ii_tag {};
struct bi_tag: public fi_tag {};
struct rai_tag: public bi_tag {};

这些类不需要成员,仅用于重载决议,继承机制使多态得以实现,例如ii与fi版本的advanced()实现相同,fi也可以使用ii版本的函数,不必再在fi版本函数中传递调用ii版本函数。

template <class I>
struct iterator_traits {
	typedef typename I::iterator_category iterator_category;
};

template <class I>
struct iterator_traits<T*> {
	// 原生指针是rai,我们总将迭代器类型认为是最强化的那一种
    typedef rai_tag iterator_category;
};

template <class I>
struct iterator_traits<const T*> {
	typedef rai_tag iterator_category;
};

template <class InputIterator, class Distance>
inline void advance(InputIterator& i, Distance n) {
	__advance(i, n, iterator_traits<InputIterator>::iterator_category());
}

template <class InputIterator, class Distance>
inline void __advance(InputIterator& i, Distance n, ii_tag) {
	while(n--) ++i;
}

template <class InputIterator, class Distance>
inline void __advance(InputIterator& i, Distance n, bi_tag) {
	if(n > 0) {
    	while(n--) ++i;
    } else {
    	while(n--) --i;
    }
}

template <class InputIterator, class Distance>
inline void __advance(InputIterator& i, Distance n, rai_tag) {
	n > 0 ? i += n : i -= n;
}

iterator

STL提供了iterator class,自设计的迭代器可以直接继承iterator,无需再自定义内嵌型别。

template <class Category, class T, class Distance = ptrdiff_t, class Pointer = T*, class Reference = T&>
struct iterator {
	typedef Category iterator_category;
    typedef T value_type;
    typedef Distance difference_type;
    typedef Pointer pointer;
    typedef Reference reference;
};

// 使用方式
template <class T>
struct Iter: public std::iterator<std::rai_tag, T> {...};

本文内容参考 —— 《STL源码剖析》