迭代器标签:
C++标准程序库为每一种迭代器提供了一个迭代器标志,用来作为迭代器的标签:
namespace std{ struct output_iterator_tag{}; struct input_iterator_tag{}; struct forward_iterator_tag:public input_iterator_tag{};//为何只派生input迭代器标签? struct bidirectional_iterator_tag:public forward_iterator_tag{}; struct random_access_iterator_tag:public bidirectional_interator_tag{}; }
Forward迭代器的某些特性不符合Output迭代器要求,详细:http://blog.csdn.net/ggz631047367/article/details/38011069
迭代器特性:
C++标准程序库提供了一种特殊的template结构定义所谓的迭代器特性(Iterator traits),该结构包含迭代器相关的所有信息,为迭代器应具备的所有型别定义(包括迭代器类型,元素型别等等)提供一致的接口:
namspace std{ template<class T> struct iterator_traits{ typedef typename T::value_type value_type; typedef typename T::difference_type difference_type; typedef typename T::iterator_category iterator_category; typedef typename T::pointer pointer; typedef typename T::reference reference; } }
T代表迭代器型别,有了它,我们就可以撰写任何运用迭代器类型或元素型别等特征的泛型程序代码。
该迭代器特性结构由两个优点:
- 能够确保每一个迭代器提供所有必要的型别定义。
- 能够针对特定迭代器进行特化。
上述第二条用于以一般指针作为迭代器时:
namspace std{ template<class T> struct iterator_traits<T*>{ typedef T value_type; typedef ptrdiff_t difference_type; typedef random_access_iterator_tag iterator_category; typedef T* pointer; typedef T& reference; } }
为迭代器编写泛型函数:
通过迭代器特征,你可以撰写这样的泛型函数:根据迭代器类型而派生型别定义或采用不同的实作码。
某些算法函数内部需要一个以元素型别为型别的暂时变量。
typename std::iterator_traits<T>::value_type temp;
如果希望针对不同的迭代器类型采用不同的实作方案,你需要按照下面两步来进行:
- 让你的template函数将迭代器类型作为附加参数,调用另一个函数。如:
template<class iterator> inline void foo(iterator beg,iterator end) { foo(beg,end,std::iterator_traits<iterator>::iterator_category()); }
- 针对不同迭代器类型实作出上述所调用的函数。只有“并非派生自其它迭代器类型”的迭代器类型,才需要提供特化版本,如:
template<class BiIterator> void foo(BiIterator beg,BiIterator end,std::bidirectional_iterator_tag) { …… }
template<class RaIterator> void foo(RaIterator beg,RaIterator end,std::random_access_iterator_tag) { …… }
distance()的实作:
template<class iterator> typename std::iterator_traits<iterator>::difference_type distance(iterator pos1,iterator pos2) { return distance(pos1,pos2,std::iterator_traits<iterator>::iterator_category()); }
template<class RaIterator> typename std::iterator_traits<RaIterator>::difference_type distance (RaIterator pos1,RaIterator pos2,std::random_access_iterator_tag) { return pos2-pos1; }
template<class InIterator> typename std::iterator_traits<InIterator>::difference_type distance (InIterator pos1,InIterator pos2,std::input_iterator_tag) { typename std::iterator_traits<InIterator>::difference_type d; for(d=0;pos1!=pos2;++pos1,++d) { ; } return d; }
第二个版本使用input迭代器,所以该版本对Forward迭代器、Bidirectional迭代器都有效。
使用自定义迭代器:
自定义迭代器,需要提供特性,有两种办法:
- 提供必要的五种型别的定义,就像iterator_traits结构所描述。
- 提供一个特化版本的iterator_traits结构
关于第一种方法,C++标准库提供了一个特殊基础类别iterator<>,专门用来进行这型别定义,你只需这样指定型别:class Myiterator:public std::iterator<std::bidirectional_iterator_tag,type,std::ptrdiff_t,type*,type&> { …… };
第一个参数用来定义迭代器类型,第二个参数用来定义元素型别,第三个参数用来定义距离型别,第四个参数用来定义pointer型别,第五个参数用来定义reference型别,最后三个参数有默认值ptrdiff_t,type*,type&,通常这样使用就够了:class Myiterator:public std::iterator<std::bidirectional_iterator_tag,type> { …… };
例子:assoiter.h:
#include<iterator> template<class Container> class asso_insert_iterator :public std::iterator < std::output_iterator_tag, void, void, void, void > { protected: Container& container;; public: explicit asso_insert_iterator(Container& c) :container(c){}; asso_insert_iterator<Container>& operator=(const typename Container::value_type& value) { container.insert(value); return *this; } asso_insert_iterator<Container>& operator*() { return *this; } asso_insert_iterator<Container>& operator++() { return *this; } asso_insert_iterator<Container>& operator++(int) { return *this; } }; template<class Container> inline asso_insert_iterator<Container> asso_inserter(Container& c) { return asso_insert_iterator<Container>(c); }
传给iterator的第一个参数output_iterator_tag指定了迭代器类型,Ouput迭代器只能用来写入,所以其余为void。test.cppvs2013:右击工程 - 属性 - 配置属性 - C/C++ - 命令行 添加:-D_SCL_SECURE_NO_WARNINGS#include <iostream> #include <set> #include<algorithm> #include"assoiter.h" using namespace std; int main() { set<int> coll; asso_insert_iterator<set<int>> iter(coll); *iter = 1; iter++; iter = 2; *iter =3; copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " ")); cout << endl; asso_inserter(coll) = 44; asso_inserter(coll) = 55; copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " ")); cout << endl; int vals[] = { 33, 67, -4, 13, 5, 2 }; copy(vals, vals + (sizeof(vals) / sizeof(vals[0])), asso_inserter(coll)); copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " ")); cout << endl; system("pause"); return 0; }
输出:
1 2 3
1 2 3 44 55
-4 1 2 3 5 13 33 44 55 67