diff --git a/iterator_adaptors.htm b/iterator_adaptors.htm index 8270a64..c46083b 100644 --- a/iterator_adaptors.htm +++ b/iterator_adaptors.htm @@ -1,819 +1,511 @@ - + + + + + -
- - - -The file boost/iterator_adaptors.hpp -includes the main iterator_adaptors class and several other classes -for constructing commonly used iterator adaptors.
+The Iterator Adaptor library allows you transform an arbitrary + ``base'' type into a standard-conforming iterator with the + behaviors you choose. Doing so is especially easy if the + ``base'' type is itself an iterator. The library also + supplies several example adaptors which + apply specific useful behaviors to arbitrary base iterators. -
The file boost/integer_range.hpp includes a class that - uses iterator adaptors to create an iterator that increments over a - range of integers. The file also includes a "container" type - that creates a container-interface for the range of integers. -
Dave
+ Abrahams started the library, applying policies class technique
+ and handling const/non-const iterator interactions. He also contributed the
+ indirect_ and reverse_ iterator generators, and expanded
+ counting_iterator_generator to
+ cover all incrementable types.
+ Jeremy
+ Siek contributed the transform
+ iterator adaptor, the integer-only version of counting_iterator_generator, and most of
+ the documentation.
+ John
+ Potter contributed the projection_ and filter_ iterator generators and made some
+ simplifications to the main iterator_adaptor template.
-
+
Dave
-Abrahams started the library, coming up with the idea to use
-policy classes and how to handle the const/non-const iterator
-interactions. He also contributed the indirect_iterators and
-reverse_iterators classes.
-
-Jeremy Siek
-contributed transform_iterator, integer_range,
-and this documentation.
-
-John Potter
-contributed indirect_iterator and projection_iterator
-and made some simplifications to iterator_adaptor.
-
-
-
--template <class Iterator, - class ConstIterator, - class Traits = std::iterator_traits<Iterator>, - class ConstTraits = std::iterator_traits<ConstIterator>, - class Policies = default_iterator_policies> -struct iterator_adaptors + |
The Iterator and ConstIterator template parameters -are the iterator types that you want to adapt. The Traits and -ConstTraits must be iterator traits classes. The traits -parameters default to the specialization of the -std::iterator_traits class for the adapted iterators. If you -want the traits for your new iterator adaptor (value_type, -iterator_category, etc.) to be the same as the adapted -iterator then use the default, otherwise create your own traits -classes and pass them in [1]. +template <class B, class Policies, class V, class R, class P, + class C, class D1, class D2> +iterator_adaptor<B,Policies,V,R,P,C,D1> +operator+(iterator_adaptor<B,P,V,R,P,C,D1>, D2); +template <class B, class Policies, class V, class R, class P, + class C, class D1, class D2> +iterator_adaptor<B,Policies,V,R,P,C,D1> +operator+(D2, iterator_adaptor<B,P,V,R,P,C,D1> p); -
The Policies class that you pass in will become the heart of -the iterator adaptor, supplying the core iterator operations that will determine how your new adaptor -class will behave. The core iterator operations are: -
dereference
- returns an element of the iterator's reference
type
-equal
- tests the iterator for equality
-increment
- increments the iterator
-decrement
- decrements bidirectional and random-access iterators
-less
- imposes a strict weak ordering relation on random-access iterators
-distance
- measures the distance between random-access iterators
-advance
- adds an integer offset to random-access iterators
--
-+template <class B1, class B2, class Policies, class V1, class V2, + class R1, class R2, class P1, class P2, class C, class D> +bool operator!=(const iterator_adaptor<B1,P,V1,R1,P1,C,D>&, + const iterator_adaptor<B2,P,V2,R2,P2,C,D>&); + +template <class B1, class B2, class Policies, class V1, class V2, + class R1, class R2, class P1, class P2, class C, class D> +bool operator<(const iterator_adaptor<B1,P,V1,R1,P1,C,D>&, + const iterator_adaptor<B2,P,V2,R2,P2,C,D>&); + +template <class B1, class B2, class Policies, class V1, class V2, + class R1, class R2, class P1, class P2, class C, class D> +bool operator<=(const iterator_adaptor<B1,P,V1,R1,P1,C,D>&, + const iterator_adaptor<B2,P,V2,R2,P2,C,D>&); + +template <class B1, class B2, class Policies, class V1, class V2, + class R1, class R2, class P1, class P2, class C, class D> +bool operator>=(const iterator_adaptor<B1,P,V1,R1,P1,C,D>&, + const iterator_adaptor<B2,P,V2,R2,P2,C,D>&); + +template <class B1, class B2, class Policies, class V1, class V2, + class R1, class R2, class P1, class P2, class C, class D> +bool operator>(const iterator_adaptor<B1,P,V1,R1,P1,C,D>&, + const iterator_adaptor<B2,P,V2,R2,P2,C,D>&); ++ + Example+ +It is often useful to automatically apply some function to the + value returned by dereferencing (operator*()) an + iterator. The transform + iterator makes it easy to create an iterator adaptor that does + just that. Here we will show how easy it is to implement the + transform iterator using the iterator_adaptor class. + +The main task in using iterator_adaptor is creating an + appropriate Policies class. + + The Policies class that you pass in will become the heart of + the iterator adaptor, supplying the core iterator operations that will + determine how your new adaptor class will behave. The core iterator + operations are: + +
+ +struct default_iterator_policies { // required for a ForwardIterator template <class Reference, class Iterator> - Reference dereference(type<Reference>, const Iterator& x) const + Reference dereference(type<Reference>, const Iterator& x) const { return *x; } template <class Iterator> - static void increment(Iterator& x) + static void increment(Iterator& x) { ++x; } template <class Iterator1, class Iterator2> - bool equal(Iterator1& x, Iterator2& y) const + bool equal(Iterator1& x, Iterator2& y) const { return x == y; } // required for a BidirectionalIterator template <class Iterator> - static void decrement(Iterator& x) + static void decrement(Iterator& x) { --x; } // required for a RandomAccessIterator template <class Iterator, class DifferenceType> - static void advance(Iterator& x, DifferenceType n) + static void advance(Iterator& x, DifferenceType n) { x += n; } template <class Difference, class Iterator1, class Iterator2> - Difference distance(type<Difference>, Iterator1& x, Iterator2& y) const + Difference distance(type<Difference>, Iterator1& x, Iterator2& y) const { return y - x; } template <class Iterator1, class Iterator2> - bool less(Iterator1& x, Iterator2& y) const + bool less(Iterator1& x, Iterator2& y) const { return x < y; } }; - |
-The generated iterator adaptor types will have the following -constructors. + + To implement a transform iterator we will only change one of the + base iterator's behaviors, so the + transform_iterator_policies class will inherit the rest + from default_iterator_policies. In addition, we will need + a function object to apply, so the policies class will have a + template parameter for the function object and it will have a data + member of that type. The function will take one argument (the + value type of the base iterator) and we will need to know the + result_type of the function, so + + AdaptableUnaryFunction is the correct concept (set of + requirements) to choose for the function object type. Inside of + transform_iterator_policies we will implement the + dereference() member function. This member function will + dereference the base iterator (the second parameter of + dereference()) and apply the function object. The + type<Reference> class used below is there to convey + the reference type of the iterator, which is handy when writing + generic iterator adaptors such as this one. The following is the + complete code for the transform_iterator_policies class. -
-
--iterator(const Iterator& i, const Policies& p = Policies()) - -const_iterator(const ConstIterator& i, const Policies& p = Policies()) - |
-
--template <class Iterator, - class Policies = default_iterator_policies, - class Traits = std::iterator_traits<Iterator> > -struct iterator_adaptor; - |
-Next we will look at some iterator adaptors that are examples of how -to use the iterator adaptors class, and that are useful iterator -adaptors in their own right. - -
-
-+ |
+ The next step is to use the iterator_adaptor class to + construct the transform iterator type. The nicest way to package + up the construction of the transform iterator is to create a type + generator, which is a class whose sole purpose is to + create a typedef for some new type based on several template + parameters. The first template parameter will be the type of the + function object and the second will be the base iterator + type. Inside the transform_iterators class we use the + iterator_adaptor class to create the transform iterator + type. -
-
-- template <class AdaptableUnaryFunction, class IteratorTraits> - struct transform_iterator_traits { - typedef typename AdaptableUnaryFunction::result_type value_type; - typedef value_type reference; - typedef value_type* pointer; - typedef typename IteratorTraits::difference_type difference_type; - typedef typename IteratorTraits::iterator_category iterator_category; - }; - |
-
--template <class AdaptableUnaryFunction, - class Iterator, - class Traits = std::iterator_traits<Iterator> - > -struct transform_iterator + |
-The following is a simple example of how to use the -transform_iterators class to iterate through a range of -numbers, multiplying each of them by 2 when they are dereferenced. +
As a finishing touch, we will create an object + generator for the transform iterator. This is a function that + makes it more convenient to create a transform iterator. +
+
+-+template <class AdaptableUnaryFunction, class Iterator> +typename transform_iterator_generator<AdaptableUnaryFunction,Iterator>::type +make_transform_iterator(Iterator base, + const AdaptableUnaryFunction& f = AdaptableUnaryFunction()) +{ + typedef typename transform_iterator_generator<AdaptableUnaryFunction, + Iterator>::type result_t; + return result_t(base, f); +} ++
-
-+ |
Parameter -To implement the indirect adaptors, we first create a policies class -which does a double-dereference in the dereference() method. + | Description
- -
| ||||
---|---|---|---|---|---|
Predicate -We then create a traits class, including a template parameter for both -the inner and outer iterators and traits classes. The -difference_type and iterator_category come from the -outer iterator, while the value_type, pointer, and -reference types come from the inner iterator. + | The function object that determines which elements are retained and
+ which elements are skipped.
- -
| ||||
BaseIterator -Lastly we wrap this up in two type generators: -indirect_iterator for creating a single indirect iterator -type, and indirect_iterators for creating an const/non-const -pair of indirect iterator types. We use the iterator_adaptor -and iterator_adaptors classes here to do most of the work. + | The iterator type being wrapped. This type must at least be a model
+ of the InputIterator concept.
- -
| The value_type of the resulting iterator, unless const. If
+ const, a conforming compiler strips constness for the
+ value_type. Typically the default for this parameter is the
+ appropriate type[1]. + Default: + std::iterator_traits<BaseIterator>::value_type + | |||
Pointer
-The Projection Iterator Adaptors+ | The pointer type of the resulting iterator, and in
+ particular, the result type of operator->(). Typically the default
+ for this parameter is the appropriate type. + Default: If Value was supplied, then Value*, + otherwise std::iterator_traits<BaseIterator>::pointer. -The projection iterator adaptor is very similar to the transform -iterator, except for a subtle difference in the return type: the -tranform iterator returns the result of the unary function by value, -whereas the projection iterator returns the result by reference. -Therefore, these two adaptors cater to different kinds of unary -functions. Transform iterator caters to functions that create new -objects, whereas projection iterator caters to a function that somehow -obtains a reference to an object that already exists. An example of a -unary function that is suitable for use with the projection adaptor is -select1st_: + | ||||
Reference
- -
| The reference type of the resulting iterator, and in
+ particular, the result type of operator*(). Typically the default for
+ this parameter is the appropriate type. + Default: If Value is supplied, Value& is + used. Otherwise + std::iterator_traits<BaseIterator>::reference is used. -The implementation of projection iterator is as follows. First, the -policies class is the same as the transform iterator's policies class. + | ||||
Category
- -
| The difference_type for the resulting iterator. Typically
+ the default for this parameter is the appropriate type. + Default: + std::iterator_traits<BaseIterator>::difference_type + |
-
--template <class AdaptableUnaryFunction, class Traits> -struct projection_iterator_traits { - typedef typename AdaptableUnaryFunction::result_type value_type; - typedef value_type& reference; - typedef value_type* pointer; - typedef typename Traits::difference_type difference_type; - typedef typename Traits::iterator_category iterator_category; -}; - -template <class AdaptableUnaryFunction, class Traits> -struct const_projection_iterator_traits { - typedef typename AdaptableUnaryFunction::result_type value_type; - typedef value_type const& reference; - typedef value_type const* pointer; - typedef typename Traits::difference_type difference_type; - typedef typename Traits::iterator_category iterator_category; -}; - |
-
--template <class AdaptableUnaryFunction, class Iterator, - class Traits = std::iterator_traits<Iterator> - > -struct projection_iterator { - typedef projection_iterator_traits<AdaptableUnaryFunction, Traits> - Projection_Traits; - typedef iterator_adaptor<Iterator, - projection_iterator_policies<AdaptableUnaryFunction>, - Projection_Traits> type; -}; - -template <class AdaptableUnaryFunction, class Iterator, - class Traits = std::iterator_traits<Iterator> - > -struct const_projection_iterator { - typedef const_projection_iterator_traits<AdaptableUnaryFunction, - Traits> Projection_Traits; - typedef iterator_adaptor<Iterator, - projection_iterator_policies<AdaptableUnaryFunction>, - Projection_Traits> type; -}; - -template <class AdaptableUnaryFunction, class Iterator, class ConstIterator, - class Traits = std::iterator_traits<Iterator>, - class ConstTraits = std::iterator_traits<ConstIterator> - > -struct projection_iterators { - typedef projection_iterator_traits<AdaptableUnaryFunction, Traits> - Projection_Traits; - typedef const_projection_iterator_traits<AdaptableUnaryFunction, - ConstTraits> Const_Projection_Traits; - typedef iterator_adaptors<Iterator, ConstIterator, - Projection_Traits, Const_Projection_Traits, - projection_iterator_policies<AdaptableUnaryFunction> > Adaptors; - typedef typename Adaptors::iterator iterator; - typedef typename Adaptors::const_iterator const_iterator; -}; - |
-Yes, there is already a reverse_iterator adaptor class -defined in the C++ Standard, but using the iterator_adaptors -class we can re-implement this classic adaptor in a more succinct and -elegant fashion. Also, this makes for a good example of using -iterator_adaptors that is in familiar territory. - -
-The first step is to create the Policies class. As in the -std::reverse_iterator class, we need to flip all the -operations of the iterator. Increment will become decrement, advancing -by n will become retreating by n, etc. - -
-
--struct reverse_iterator_policies -{ - template <class Reference, class Iterator> - Reference dereference(type<Reference>, const Iterator& x) const - { return *boost::prior(x); } - // this is equivalent to { Iterator tmp = x; return *--tmp; } - template <class Iterator> - void increment(Iterator& x) const - { --x; } - - template <class Iterator> - void decrement(Iterator& x) const - { ++x; } - - template <class Iterator, class DifferenceType> - void advance(Iterator& x, DifferenceType n) const - { x -= n; } - - template <class Difference, class Iterator1, class Iterator2> - Difference distance(type<Difference>, Iterator1& x, Iterator2& y) const - { return x - y; } - - template <class Iterator1, class Iterator2> - bool equal(Iterator1& x, Iterator2& y) const - { return x == y; } - - template <class Iterator1, class Iterator2> - bool less(Iterator1& x, Iterator2& y) const - { return y < x; } -}; - |
There is an unlimited number of ways the the + iterator_adaptors class can be used to create + iterators. One interesting exercise would be to re-implement the + iterators of std::list and std::slist using + iterator_adaptors, where the adapted Iterator + types would be node pointers. -
-
--template <class Iterator, class ConstIterator, - class Traits = std::iterator_traits<Iterator>, - class ConstTraits = std::iterator_traits<ConstIterator> - > -struct reverse_iterators -{ - typedef iterator_adaptors<Iterator,ConstIterator,Traits,ConstTraits, - reverse_iterator_policies> Adaptor; - typedef typename Adaptor::iterator iterator; - typedef typename Adaptor::const_iterator const_iterator; -}; - |
[1] If your compiler does not support partial + specialization and the base iterator is a builtin pointer type, + then you will not be able to use the default for Value + and will need to explicitly specify this type. -
-
--class my_container { - ... - typedef ... iterator; - typedef ... const_iterator; + |
Revised + 10 + Feb 2001 -
© Copyright Jeremy Siek and Dave Abrahams 2001. Permission to copy, use, modify, sell + and distribute this document is granted provided this copyright notice + appears in all copies. This document is provided "as is" without express or + implied warranty, and with no claim as to its suitability for any purpose. -The iterator_adaptors class can not only be used for adapting -iterators, but it can also be used to take a non-iterator type and use -it to build an iterator. An especially simple example of this is -turning an integer type into an iterator, a counting iterator. The -builtin integer types of C++ are almost iterators. They have -operator++(), operator--(), etc. The one operator -they are lacking is the operator*(), which we will want to -simply return the current value of the integer. The following few -lines of code implement the policy and traits class for the counting -iterator. - -
-
--template <class IntegerType> -struct counting_iterator_policies : public default_iterator_policies -{ - IntegerType dereference(type<IntegerType>, const IntegerType& i) const - { return i; } -}; -template <class IntegerType> -struct counting_iterator_traits { - typedef IntegerType value_type; - typedef IntegerType reference; - typedef value_type* pointer; - typedef std::ptrdiff_t difference_type; - typedef std::random_access_iterator_tag iterator_category; -}; - |
-
--template <class IntegerType> -struct integer_range { - typedef typename iterator_adaptor<IntegerType, - counting_iterator_traits<IntegerType>, - counting_iterator_policies >::type iterator; - typedef iterator const_iterator; - typedef IntegerType value_type; - typedef std::ptrdiff_t difference_type; - typedef IntegerType reference; - typedef IntegerType* pointer; - typedef IntegerType size_type; - - integer_range(IntegerType start, IntegerType finish) - : m_start(start), m_finish(finish) { } - - iterator begin() const { return iterator(m_start); } - iterator end() const { return iterator(m_finish); } - size_type size() const { return m_finish - m_start; } - bool empty() const { return m_finish == m_start; } - void swap(integer_range& x) { - std::swap(m_start, x.m_start); - std::swap(m_finish, x.m_finish); - } -protected: - IntegerType m_start, m_finish; -}; - |
-The following is an example of how to use the -integer_range class to count from 0 to 4. - -
-
--boost::integer_range<int> r(0,5); - -cout << "counting to from 0 to 4:" << endl; -std::copy(r.begin(), r.end(), ostream_iterator<int>(cout, " ")); -cout << endl; - |
-There is an unlimited number of ways the the -iterator_adaptors class can be used to create iterators. One -interesting exercise would be to re-implement the iterators of -std::list and std::slist using -iterator_adaptors, where the adapted Iterator types -would be node pointers. - - -
-[1] -If your compiler does not support partial specialization and hence -does not have a working std::iterator_traits class, you will -not be able to use the defaults and will need to supply your own -Traits and ConstTraits classes. - -
-[2] -The reference type could also be obtained from -std::iterator_traits, but that is not portable on compilers -that do not support partial specialization. - -
-[3] -It would have been more elegant to implement indirect_iterators -using transform_iterators, but for subtle reasons that would require -the use of boost::remove_cv which is not portable. - -
Revised 10 Feb 2001
-© Copyright Jeremy Siek 2000. Permission to copy, use, -modify, sell and distribute this document is granted provided this copyright -notice appears in all copies. This document is provided "as is" -without express or implied warranty, and with no claim as to its suitability for -any purpose.
- - - - + + + + + +