Take a simple advance as example, you might design:dom
template<class II, class D> void advance(II& i, D n){ while( n-- ) ++i; }
However it have O(n) complexity, which is not acceptable when you have a random_access_iterator. So you may change your design like this:ide
template<class II, class D> void advance_II(II& i, D n){ while( n-- ) ++i; } template<class RAI, class D> void advance_RAI(RAI& i, D n){ i += n; } template<class II, class D> void advance(II& i, D n){ if(is_random_access_iterator(i)) // not yet designed advance_RAI(i, n); else advance_II(i, n); }
However the version of function to use is decided at run-time, so we try to let compiler decided which method to choose at compile-time. So we give iterators tags. There are five tags:this
struct input_iterator_tag {}; struct output_iterator_tag {}; struct forward_iterator_tag : public input_iterator_tag {}; struct bidirection_iterator_tag : public forward_iterator_tag {}; struct random_access_iterator_tag : public bidirection_iterator_tag {};
Now you can do this:spa
template<class II, class D> void __advance(II& i, D n, input_iterator_tag){ while( n-- ) ++i; } template<class RAI, class D> void __advance(RAI& i, D n, random_access_iterator_tag){ i += n; } template<class II, class D> void advance(II& i, D n){ __advance(i, n, iterator_traits<II>::iterator_category()); }