让我们来看一个简单地例子:advance函数,四种不同类型的Iterator会有不同的实现方式:
// input iterator和forward iterator的版本
template <class InputIterator, class Distance>
void advance1(InputIterator& i, Distance n) {
while (n--) ++i; // 只能单向向前移动
}
//Bidirectional iterator的版本
template <class BidirectionalIterator, class Distance>
void advance2(BidirectionalIterator& i, Distance n) {
if (n >= 0) // 根据方向不同做不同处理
while (n--) ++i;
else
while (n++) --i;
}
//Random access iterator的版本
template <class RandomAccessIterator, class Distance>
void advance3(RandomAccessIterator& i, Distance n) {
i += n; // 效率最高
}
我们显然也无法选择其中一种作为四者通用,否则将面临功能错误或者效率牺牲。
考虑加一场外覆层,把三者结合起来:
template <class Iterator, class Distance>
void advance(Iterator& i, Distance n) {
if(is_random_access_iterator(i))
advance3(i,n);
else if(is_bidirectional_iterator(i))
advance2(i,n);
else
advance1(i,n);
}
但是这样需要在运行时才作出选择,牺牲了效率,是否有编译时选择的版本呢?这里函数重载就派上用场了,编译重载函数时可以根据函数参数类型选择重载函数。那么有如下实现:
// input iterator和forward iterator的版本
template <class InputIterator, class Distance>
inline void advance(InputIterator& i, Distance n, input_iterator_tag) {
while (n--) ++i; // 只能单向向前移动
}
//Bidirectional iterator的版本
template <class BidirectionalIterator, class Distance>
inline void advance(BidirectionalIterator& i, Distance n,
bidirectional_iterator_tag) {
if (n >= 0) // 根据方向不同做不同处理
while (n--) ++i;
else
while (n++) --i;
}
//Random access iterator的版本
template <class RandomAccessIterator, class Distance>
inline void __advance(RandomAccessIterator& i, Distance n,
random_access_iterator_tag) {
i += n; // 效率最高
}
调用时对于input_iterator,则可以用advance(i,n,input_iterator_tag());
其他类型以此类推;
我们可以让每个Iterator都有一个相应的Iterator category type(迭代器类型),和其他associated type一样,Iterator category 可以定义为Iterator_traits的内嵌类型:
template <class Iterator, class Distance>
inline void advance(Iterator& i, Distance n) {
advance(i,n, typename iterator_traits<Iterator>::iterator_category());
}
STL把五个tag tyes定义为五个空类:
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 {};
这些tag types都是class,而且有继承关系,此点其实无关紧要,重要的是他们独一无二,都各代表一种迭代器类型。
完整的Iterator_traints
有了前面的铺垫,让我们来看一个完整的Iterator_traits:
//class类型Iterator
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;
};
//指针类型Iterator
template <class T>
struct iterator_traits<T*> {
typedef random_access_iterator_tag iterator_category; // 指针类型是可以随机访问的
typedef T value_type; // 值类型
typedef ptrdiff_t difference_type; // 指针类型之间的距离一定是整型(ptrdiff_t被定义为int型)
typedef T* pointer;
typedef T& reference;
};
//常量指针Iterator
template <class T>
struct iterator_traits<const T*> {
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef const T* pointer;
typedef const T& reference;
};
当定义一个新的Iterator class,你必须在这个class中定义这五个嵌套类型,STL内含一个base class iterator,使事情更加简化。
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 Pointer pointer;
typedef Reference reference;
typedef Category iterator_category;
};
当我们需要定义一个新的Iterator class时,就可以继承这个base Iterator了。
// std::iterator example
#include <iostream> // std::cout
#include <iterator> // std::iterator, std::input_iterator_tag
class MyIterator : public std::iterator<std::input_iterator_tag, int>
{
int* p;
public:
MyIterator(int* x) :p(x) {}
MyIterator(const MyIterator& mit) : p(mit.p) {}
MyIterator& operator++() {++p;return *this;}
MyIterator operator++(int) {MyIterator tmp(*this); operator++(); return tmp;}
bool operator==(const MyIterator& rhs) {return p==rhs.p;}
bool operator!=(const MyIterator& rhs) {return p!=rhs.p;}
int& operator*() {return *p;}
};
int main () {
int numbers[]={10,20,30,40,50};
MyIterator from(numbers);
MyIterator until(numbers+5);
for (MyIterator it=from; it!=until; it++)
std::cout << *it << ' ';
std::cout << '\n';
return 0;
}
From: http://www.cplusplus.com/reference/iterator/iterator/
(base iterator不含有任何member functions和member variables,所以继承他不会引起任何额外开销)