From e104b00da190a9cc14158f8638d3158a1095bfe6 Mon Sep 17 00:00:00 2001 From: Jeremy Siek Date: Tue, 13 Feb 2001 04:15:17 +0000 Subject: [PATCH] merged in Dave's additions and added a tutorial using the implementation of transform iterator as the example [SVN r9182] --- iterator_adaptors.htm | 1134 +++++++++++++++-------------------------- 1 file changed, 413 insertions(+), 721 deletions(-) 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 @@ - + + + + + - - - - -Header boost/iterator_adaptors.hpp Documentation - + - + Boost Iterator Adaptor Library -c++boost.gif (8819 bytes) + c++boost.gif (8819 bytes) -

Header -boost/iterator_adaptors.hpp -and -boost/integer_range.hpp

+

Boost Iterator Adaptor Library

-

The file boost/iterator_adaptors.hpp -includes the main iterator_adaptors class and several other classes -for constructing commonly used iterator adaptors.

+

Introduction

- +

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. -

+

Table of Contents

+ + + + + +

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.
- +

Template class + iterator_adaptor

+ Implementing standard conforming iterators is a non-trivial task. There are + some fine points such as the interactions between an iterator and its + corresponding const_iterator, and there are myriad operators that should be + implemented but are easily forgotten or mishandled, such as + operator->(). Using iterator_adaptor, you can easily + implement an iterator class, and even more easily extend and adapt existing iterator + types. Moreover, it is easy to make a pair of interoperable const + and non-const iterators. -

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. - -

The Iterator Adaptors Class

- -Implementing standard conforming iterators is a non-trivial task. -There are some fine-points such as iterator/const_iterator -interactions and there are the myriad of operators that should be -implemented but are easily forgotten such as -operator->(). The purpose of the -iterator_adaptors class is to make it easier to implement an -iterator class, and even easier to extend and adapt existing iterator -types. The iterator_adaptors class itself is not an adaptor -class but a type generator. It generates a pair of adaptor classes, -one class for the mutable iterator and one class for the const -iterator. The definition of the iterator_adaptors class is as -follows: - -

- -
-
-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
+    

Synopsis

+
+template <class Base, class Policies, 
+    class Value = typename std::iterator_traits<Base>::value_type,
+    class Reference = ...(see below),
+    class Pointer = ...(see below),
+    class Category = typename std::iterator_traits<Base>::iterator_category,
+    class Distance = typename std::iterator_traits<Base>::difference_type
+         >
+struct iterator_adaptor;
 {
-  typedef ... iterator;
-  typedef ... const_iterator;
+    typedef Distance difference_type;
+    typedef typename boost::remove_const<Value>::type value_type;
+    typedef Pointer pointer;
+    typedef Reference reference;
+    typedef Category iterator_category;
+    typedef Base base_type;
+
+    iterator_adaptor();
+    iterator_adaptor(const Base&, const Policies& = Policies());
+
+    base_type base() const;
+
+    template <class Iter2, class Value2, class Pointer2, class Reference2>
+    iterator_adaptor (
+        const iterator_adaptor<Iter2,Policies,Value2,Reference2,Pointer2,Category,Distance>&
+            : m_iter_p(src.iter(), src.policies());
+
+    reference operator*() const;
+    operator_arrow_result_type operator->() const; [2]
+    value_type operator[](difference_type n) const;
+
+    iterator_adaptor& operator++();
+    iterator_adaptor& operator++(int);
+    iterator_adaptor& operator--();
+    iterator_adaptor& operator--(int);
+
+    iterator_adaptor& operator+=(difference_type n);
+    iterator_adaptor& operator-=(difference_type n);
+
+    iterator_adaptor& operator-(Distance x) const;
 };
-
-

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: -

-The Policies class must implement three, four, or -seven of the core iterator operations depending on whether you wish the -new iterator adaptor class to be a - -ForwardIterator, - -BidirectionalIterator, or -RandomAccessIterator. The -iterator_category type of the traits class you pass in -must match the category of iterator that you want to create. The default -policy class, default_iterator_policies, implements all 7 of -the core operations in the usual way. If you wish to create an -iterator adaptor that only changes a few of the iterator's behaviors, -then you can have your new policy class inherit from -default_iterator_policies to avoid retyping the usual -behaviours. You should also look at default_iterator_policies -as the "boiler-plate" for your own policy classes. The -following is definition of the default_iterator_policies -class: +template <class B1, class B2, class Policies, class V1, class V2, + class R1, class R2, class P1, class P2, class C, class D> +Distance 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>&);
+
+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: + +

    +
  • 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 +
+ The Policies class must implement three, four, or seven of the + core iterator operations depending on whether you wish the new iterator + adaptor class to be a ForwardIterator, + BidirectionalIterator, + or RandomAccessIterator. + The iterator_category type of the traits class you pass in must + match the category of iterator that you want to create. The default policy + class, default_iterator_policies, implements all 7 of the core + operations in the usual way. If you wish to create an iterator adaptor that + only changes a few of the iterator's behaviors, then you can have your new + policy class inherit from default_iterator_policies to avoid + retyping the usual behaviors. You should also look at + default_iterator_policies as the ``boiler-plate'' for your own + policy classes. The following is definition of the + default_iterator_policies class: + +

+

+
 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())
-
- -

The Iterator Adaptor Class

- -This is the class used inside of the iterator_adaptors type -generator. Use this class directly (instead of using -iterator_adaptors) when you are interested in creating only -one of the iterator types (either const or non-const) or when there is -no difference between the const and non-const versions of the iterator -type (often this is because there is only a const (read-only) version -of the iterator, as is the case for std::set's iterators). - -

- -
-
-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 Transform Iterator Class

- -It is often useful to automatically apply some function to the value -returned by dereferencing (operator*()) an iterator. The -transform_iterators class makes it easy to create an iterator -adaptor that does just that. - -First let us consider what the Policies class for the transform -iterator should look like. We are only changing one of the iterator -behaviours, so we will inherit from -default_iterator_policies. In addition, we will need a -function object to apply, so we will have a template parameter and a -data member for the function object. The function will take one -argument (the dereferenced value) and we will need to know the -result_type of the function, so -AdaptableUnaryFunction is the corrent concept to choose for the -function object type. Now for the heart of our iterator adaptor, we -implement the dereference method, applying the function -object to *i. The type<Reference> class is -there to tell you what the reference type of the iterator is, which is -handy when writing generic iterator adaptors such as this one [2]. - - -

- -
-
+    

+

+
   template <class AdaptableUnaryFunction>
   struct transform_iterator_policies : public default_iterator_policies
   {
     transform_iterator_policies() { }
-    transform_iterator_policies(const AdaptableUnaryFunction& f) : m_f(f) { }
+    transform_iterator_policies(const AdaptableUnaryFunction& f) : m_f(f) { }
 
-    template <class Reference, class Iterator>
-    Reference dereference(type<Reference>, const Iterator& i) const
+    template <class Reference, class BaseIterator>
+    Reference dereference(type<Reference>, const BaseIterator& i) const
       { return m_f(*i); }
 
     AdaptableUnaryFunction m_f;
   };
-
+ + -Next we need to create the traits class for our new iterator. In some -situations you may need to create a separate traits class for the -const and non-const iterator types, but here a single traits class -will do. The value_type and reference type of our -transform iterator will be the result_type of the function -object. The difference_type and iterator_category -will be the same as the adapted iterator. +

+ 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;
-  };
-
- -The final step is to use the iterator_adaptor class to -construct our transform iterator. We will use the single iterator -adaptor version because we will not need to create both a mutable and -const version of the transform iterator. The transform iterator is -inherently a read-only iterator. The nicest way to package up our new -transform iterator is to create a type generator similar to -iterator_adaptor. The first template parameter will be the -type of the function object. The second parameter will be the adapted -iterator type. The third parameter is the trait class for -the adapted iterator. Inside the transform_iterators class -we use the transform_iterator_traits class defined above to -create the traits class for the new transform iterator. We then use -the iterator_adaptor class to extract the generated -iterator adaptor type. - -

- -
-
-template <class AdaptableUnaryFunction,
-          class Iterator,
-          class Traits = std::iterator_traits<Iterator>
-         >
-struct transform_iterator
+    

+

+
+template <class AdaptableUnaryFunction, class Iterator>
+struct transform_iterator_generator
 {
-  typedef transform_iterator_traits<AdaptableUnaryFunction,Traits>
-    TransTraits;
-  typedef iterator_adaptor<Iterator, TransTraits,
-    transform_iterator_policies<AdaptableUnaryFunction> >::type type;
+    typedef typename AdaptableUnaryFunction::result_type value_type;
+public:
+    typedef iterator_adaptor<Iterator, 
+        transform_iterator_policies<AdaptableUnaryFunction>,
+        value_type, value_type, value_type*, std::input_iterator_tag>
+      type;
 };
-
+ + -

-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);
+}
+
+
-

- -
-
+    

The following is an example of how to use a transform iterator + to iterate through a range of numbers, multiplying each of them by + 2 when they are dereferenced and printing the result to standard + output. + +

+

+
 #include <functional>
+#include <algorithm>
 #include <iostream>
 #include <boost/iterator_adaptors.hpp>
 
-int
-main(int, char*[])
+int main(int, char*[])
 {
   int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
-
-  typedef std::binder1st< std::multiplies<int> > Function;
-  typedef boost::transform_iterator<Function, int*, 
-    boost::iterator<std::random_access_iterator_tag, int>
-  >::type doubling_iterator;
-
-  doubling_iterator i(x, std::bind1st(std::multiplies<int>(), 2)),
-    i_end(x + sizeof(x)/sizeof(int), std::bind1st(std::multiplies<int>(), 2));
-
+  const int N = sizeof(x)/sizeof(int);
   std::cout << "multiplying the array by 2:" << std::endl;
-  while (i != i_end)
-    std::cout << *i++ << " ";
+  std::copy(boost::make_transform_iterator(x, std::bind1st(std::multiplies<int>(), 2)),
+	    boost::make_transform_iterator(x + N, std::bind1st(std::multiplies<int>(), 2)),
+	    std::ostream_iterator<int>(std::cout, " "));
   std::cout << std::endl;
-
   return 0;
 }
-
+ + -

The Indirect Iterator Adaptors

+

Template Parameters

-It is not all that uncommon to create data structures that consist of -pointers to pointers. For such a structure it might be nice to have an -iterator that applies a double-dereference inside the -operator*(). The implementation of this is similar to the -transform_iterators[3]. When talking about a -data structure of pointers to pointers (or more generally, iterators -to iterators), we call the first level iterators the outer -iterators and the second level iterators the inner -iterators. For example, if the outer iterator type is T** -then the inner iterator type is T*. + + + + + + + +
Parameter -To implement the indirect adaptors, we first create a policies class -which does a double-dereference in the dereference() method. + Description -

- -
-
-struct indirect_iterator_policies : public default_iterator_policies
-{
-    template <class Reference, class Iterator>
-    Reference dereference(type<Reference>, const Iterator& x) const
-        { return **x; }
-};
-
+

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. -

- -
-
-template <class OuterIterator, class InnerIterator,
-          class OuterTraits = std::iterator_traits<OuterIterator>,
-          class InnerTraits = std::iterator_traits<InnerIterator>
-         >
-struct indirect_traits
-{
-    typedef typename OuterTraits::difference_type difference_type;
-    typedef typename InnerTraits::value_type value_type;
-    typedef typename InnerTraits::pointer pointer;
-    typedef typename InnerTraits::reference reference;
-    typedef typename OuterTraits::iterator_category iterator_category;
-};
-
+

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. -

- - +
-
-template <class OuterIterator, class InnerIterator,
-          class OuterTraits = std::iterator_traits<OuterIterator>,
-          class InnerTraits = std::iterator_traits<InnerIterator>
-         >
-struct indirect_iterator
-{
-    typedef iterator_adaptor<OuterIterator,
-        indirect_iterator_policies,
-        indirect_traits<OuterIterator, InnerIterator,
-                        OuterTraits, InnerTraits>
-    > type;
-};
+      
Value -template <class OuterIterator, // Mutable or Immutable, does not matter - class InnerIterator, // Mutable - class ConstInnerIterator, // Immutable - class OuterTraits = std::iterator_traits<OuterIterator>, - class InnerTraits = std::iterator_traits<InnerIterator>, - class ConstInnerTraits = std::iterator_traits<ConstInnerIterator> - > -struct indirect_iterators -{ - typedef iterator_adaptors<OuterIterator, OuterIterator, - indirect_traits<OuterIterator, InnerIterator, - OuterTraits, InnerTraits>, - indirect_traits<OuterIterator, ConstInnerIterator, - OuterTraits, ConstInnerTraits>, - indirect_iterator_policies - > Adaptors; - typedef typename Adaptors::iterator iterator; - typedef typename Adaptors::const_iterator const_iterator; -}; -
+

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 -

- -
-
-template <class Pair>
-struct select1st_ 
-  : public std::unary_function<Pair, typename Pair::first_type>
-{
-  const typename Pair::first_type& operator()(const Pair& x) const {
-    return x.first;
-  }
-  typename Pair::first_type& operator()(Pair& x) const {
-    return x.first;
-  }
-};
-
+

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 -

- - +
-
-template <class AdaptableUnaryFunction>
-struct projection_iterator_policies : public default_iterator_policies
-{
-    projection_iterator_policies() { }
-    projection_iterator_policies(const AdaptableUnaryFunction& f) : m_f(f) { }
+        
The iterator_category type for the resulting iterator. + Typically the default for this parameter is the appropriate type. If + you override this parameter, do not use + bidirectional_iterator_tag because filter iterators can not go + in reverse.
+ Default: + std::iterator_traits<BaseIterator>::iterator_category - template <class Reference, class Iterator> - Reference dereference (type<Reference>, Iterator const& iter) const { - return m_f(*iter); - } +
Distance - AdaptableUnaryFunction m_f; -}; -
+

The difference_type for the resulting iterator. Typically + the default for this parameter is the appropriate type.
+ Default: + std::iterator_traits<BaseIterator>::difference_type +
-Next we have two traits classes. We use value_type& for the -reference type of the mutable projection iterator, and const -value_type& for the immutable projection iterator. - -

- -
-
-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;
-};
-
- -And to finish up, we create three generator classes that -use iterator_adaptor to create the projection iterator -types. The class projection_iterator creates a mutable -projection iterator type. The class const_projection_iterator -creates an immutable projection iterator type, and -projection_iterators creates both mutable and immutable -projection iterator types. - -

- -
-
-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;
-};
-
- - -

The Reverse Iterators Class

- -

-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; }
-};
-
+

Challenge

-Since the traits of the reverse iterator adaptor will be the same as -the adapted iterator's traits, we do not need to create new traits -classes as was the case for transform_iterator. We can skip to -the final stage of creating a type generator class for our reverse -iterators using the iterator_adaptor class. +

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;
-};
-
+

Notes

-A typical use of the reverse_iterators class is in -user-defined container types. You can use the -reverse_iterators class to generate the reverse iterators for -your container. +

[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;
+    

[2] The result type for the operator->() + depends on the category and value type of the iterator and + is somewhat complicated to describe. But be assured, it works + in a stardard corforming fashion, providing access to members + of the objects pointed to by the iterator. - typedef reverse_iterators<iterator, const_iterator> RevIters; - typedef typename RevIters::iterator reverse_iterator; - typedef typename RevIters::const_iterator const_reverse_iterator; - ... -}; -

+


+

Revised + 10 + Feb 2001 -

The Integer Range Class

+

© 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;
-};
-
- -Typically we will want to count the integers in some range, so a nice -interface would be to have a fake container that represents the range -of integers. The following is the definition of such a class called -integer_range. - -

- -
-
-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;
-
- -

Challenge

- -

-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. - - -

Notes

- -

-[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. - -

Implementation Notes

- -The code is somewhat complicated because there are three iterator -adaptor class: forward_iterator_adaptor, -bidirectional_iterator_adaptor, and -random_access_iterator_adaptor. The alternative would be to -just have one iterator adaptor equivalent to the -random_access_iterator_adaptor. The reason for going with -the three adaptors is that according to 14.5.3p5 in the C++ Standard, -friend functions defined inside a template class body are instantiated -when the template class is instantiated. This means that if we only -used the one iterator adaptor, then if the adapted iterator did not -meet all of the requirements for a - -RandomAccessIterator then a compiler error should occur. Many -current compilers in fact do not instantiate the friend functions -unless used, so we could get away with the one iterator adaptor in -most cases. However, out of respect for the standard this implementation -uses the three adaptors. - - - -
-

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.

- - - - + + + + + +