__iterator_traits技法用于提起迭代器iterator的相应类型
1.设计类
2.设计类的迭代器
迭代器要满足STL的要求,那么你的迭代器就能用在STL算法。
Output iterator,只写
Forward iterator,可读写
Bidirection iterator,可双向移动
先看下面是一个例子:
template <class I, class T> void func_impl(I iter, T t) { // ... } template<class I> inline void func(I iter) { func_impl(iter, *iter); // ... } int main() { int i; func(&i); return 0; }
这里利用了function template的参数推导机制。“template参数推导技术”只是推出参数,无法推导返回值,怎么办?我们可以在迭代器里内嵌一个型别声明。如下:
template<class T> struct MyIter { typedef T value_type; // .... }; template<class I> typename I::value_type func(T iter) { return *iter; }
通过在迭代器类里面嵌入一个声明,解决了推导返回值的问题(注意:上面要用typename,因为MyIter是个模板,编译器对T模板参数一无所知)!但问题又来了,并不是所有类型(如int *)都是calss type,所以无法为它定义内嵌型别,template partial specialization(模板偏特化)可以做到,但要用另一个模板作为中间层进而偏特化(这里就是__iterator_traits技法了),如下:
//__iterator_traits template<class I> struct iterator_traits { typedef typename I::value_type value_type; }; //__iterator_traits偏特化版本,准确接受内置指针类型 template<class I> struct iterator_traits<T*> { typedef T value_type; }; //接受指向const类型数据的指针 template<class I> struct iterator_traits<const T*> { typedef T value_type; };所以,STL里的算法模板都是这样实现,如果我们要设计与STL水乳交融的类,那就要符合STL的一些基本要求了。
1.设计类
2.设计类的迭代器
迭代器要满足STL的要求,那么你的迭代器就能用在STL算法。
STL中有5种迭代器,为了激活重载机制,定义的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{};Iuput iterator,只读
Output iterator,只写
Forward iterator,可读写
Bidirection iterator,可双向移动
Random Access iterator,前四种提供基本操作(operator++,第四种在加上operator--),这种包含所有指针算术能力(p+n,p-n,p[n],p1<p2...)
为了定义自己的迭代器,可以继承自下面的iterator类,避免迭代器型别的未定义。
//Base class for iterator class 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; };
iterator_traits类,就是一些typedef,相当于就是将迭代器的最本质的类型忠实的呈现出来。这里值得注意的是,要使得这个迭代器忠实的完成这项工作,那么各个迭代器的定义就必须定义相应的5个性别。value_type、 difference_type、 iterator_category、pointer、 reference .
template<class Iterator> struct iterator_traits { typedef typename 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_traits的特化版本。
template<class T> struct iterator_traits<T*> { typedef random_access_iterator_tag iterator_category; typedef T value_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef T & reference; }; 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; };下面的函数则是直接返回各个型别的类型:
template<class Iterator> inline typename iterator_traits<Iterator>::iterator_category iterator_category(const Iterator&) { typedef typename iterator_traits<Iterator>::iterator_category category; return category(); //random_access_iterator_tag or bidirectional_iterator_tag ... } //pointer to the difference_type template< class Iterator> inline typename iterator_traits<Iterator>::difference_type* distance_type (const Iterator &) { return static_cast<typename iterator_traits<Iterator>::difference_type *>(0); } template< class Iterator> inline typename iterator_traits<Iterator>::value_type * value_type (const Iterator &) { return static_cast<typename iterator_traits<Iterator>::value_type* > (0); }distance函数在上述traits下的实现代码:
//distance function template<class InputIterator> inline iterator_traits<InputIterator>::difference_type __distance(InputIterator first, InputIterator last, input_iterator_tag) { iterator_traits<InputIterator>::difference_type n=0; while(first != last) { ++first;++n; } return n; } template<class RandomIterator> inline typename iterator_traits<RandomIterator>::difference_type __distance(RandomIterator first, RandomIterator last, random_access_iterator_tag) { return last-first; } //user template<class InputIterator> inline iterator_traits<InputIterator>::difference_type distance(InputIterator first, InputIterator last) { typedef typename iterator_traits<InputIterator>::iterator_category category; return __distance(first,last,category());//category()构造一个临时对象,进行参数推导,决定重载函数。 }
以下是advance
template<class InputIterator, class Distance> inline void __advance(InputIterator &i, Distance n, input_iterator_tag) { while (n--)++i; } template<class ForwardIterator, class Distance> inline void __advance(ForwardIterator &i, Distance n, forward_iterator_tag) { __advance(i, n, input_iterator_tag()); } template<class BidirectionIterator, class Distance> inline void __advance(BidirectionIterator &i, Distance n, bidirectional_iterator_tag) { if (n >= 0) while(n--) ++i; else while(n++) --i; } template<class RandomAccessIterator, class Distance> inline void __advance(RandomAccessIterator &i, Distance n, random_access_iterator_tag) { i += n; } template<class Iterator, class Distance> inline void advance(Iterator &i, Distance n) { __advance(i, n, iterator_traits<Iterator>::iterator_category()); }
来源:STL源码剖析