diff --git a/call_traits_test.cpp b/call_traits_test.cpp index 0c7155e..3e5a1ed 100644 --- a/call_traits_test.cpp +++ b/call_traits_test.cpp @@ -16,7 +16,7 @@ #include #include -#include "type_traits_test.hpp" +#include // // struct contained models a type that contains a type (for example std::pair) // arrays are contained by value, and have to be treated as a special case: @@ -98,18 +98,18 @@ std::pair< using namespace std; // -// struct checker: +// struct call_traits_checker: // verifies behaviour of contained example: // template -struct checker +struct call_traits_checker { typedef typename boost::call_traits::param_type param_type; void operator()(param_type); }; template -void checker::operator()(param_type p) +void call_traits_checker::operator()(param_type p) { T t(p); contained c(t); @@ -117,18 +117,19 @@ void checker::operator()(param_type p) assert(t == c.value()); assert(t == c.get()); assert(t == c.const_get()); - +#ifndef __ICL //cout << "typeof contained<" << typeid(T).name() << ">::v_ is: " << typeid(&contained::v_).name() << endl; cout << "typeof contained<" << typeid(T).name() << ">::value() is: " << typeid(&contained::value).name() << endl; cout << "typeof contained<" << typeid(T).name() << ">::get() is: " << typeid(&contained::get).name() << endl; cout << "typeof contained<" << typeid(T).name() << ">::const_get() is: " << typeid(&contained::const_get).name() << endl; cout << "typeof contained<" << typeid(T).name() << ">::call() is: " << typeid(&contained::call).name() << endl; cout << endl; +#endif } #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template -struct checker +struct call_traits_checker { typedef typename boost::call_traits::param_type param_type; void operator()(param_type t) @@ -176,32 +177,32 @@ void check_make_pair(T c, U u, V v) } -struct UDT +struct comparible_UDT { int i_; - UDT() : i_(2){} - bool operator == (const UDT& v){ return v.i_ == i_; } + comparible_UDT() : i_(2){} + bool operator == (const comparible_UDT& v){ return v.i_ == i_; } }; -int main() +int main(int argc, char *argv[ ]) { - checker c1; - UDT u; + call_traits_checker c1; + comparible_UDT u; c1(u); - checker c2; + call_traits_checker c2; int i = 2; c2(i); int* pi = &i; #if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES) - checker c3; + call_traits_checker c3; c3(pi); - checker c4; + call_traits_checker c4; c4(i); - checker c5; + call_traits_checker c5; c5(i); #if !defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) int a[2] = {1,2}; - checker c6; + call_traits_checker c6; c6(a); #endif #endif @@ -220,10 +221,10 @@ int main() typedef int& r_type; typedef const r_type cr_type; - type_test(UDT, boost::call_traits::value_type) - type_test(UDT&, boost::call_traits::reference) - type_test(const UDT&, boost::call_traits::const_reference) - type_test(const UDT&, boost::call_traits::param_type) + type_test(comparible_UDT, boost::call_traits::value_type) + type_test(comparible_UDT&, boost::call_traits::reference) + type_test(const comparible_UDT&, boost::call_traits::const_reference) + type_test(const comparible_UDT&, boost::call_traits::param_type) type_test(int, boost::call_traits::value_type) type_test(int&, boost::call_traits::reference) type_test(const int&, boost::call_traits::const_reference) @@ -271,9 +272,7 @@ int main() test_count += 20; #endif - std::cout << std::endl << test_count << " tests completed (" << failures << " failures)... press any key to exit"; - std::cin.get(); - return failures; + return check_result(argc, argv); } // @@ -364,3 +363,15 @@ template struct call_traits_test; #endif #endif +#ifdef BOOST_MSVC +unsigned int expected_failures = 10; +#elif defined(__BORLANDC__) +unsigned int expected_failures = 2; +#elif defined(__GNUC__) +unsigned int expected_failures = 4; +#else +unsigned int expected_failures = 0; +#endif + + + diff --git a/iterator_adaptors.htm b/iterator_adaptors.htm index 7bfa3cd..c471a4e 100644 --- a/iterator_adaptors.htm +++ b/iterator_adaptors.htm @@ -1,819 +1,789 @@ - + + - - - -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 policy 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. He edited most of the documentation, + sometimes heavily.
+ Jeremy + Siek contributed the transform + iterator adaptor, the integer-only version of counting_iterator_generator, + the function output iterator + adaptor, and most of the documentation.
+ John + Potter contributed the projection_ and filter_ iterator generators and made some + simplifications to the main iterator_adaptor template.
- +

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

iterator_adaptor is declared like this: +

+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;
+
-Jeremy Siek -contributed transform_iterator, integer_range, -and this documentation.
+

Template Parameters

-John Potter -contributed indirect_iterator and projection_iterator -and made some simplifications to iterator_adaptor. +

Although iterator_adaptor takes seven template parameters, + defaults have been carefully chosen to minimize the number of parameters + you must supply in most cases, especially if BaseType is an + iterator. -

The Iterator Adaptors Class

+ + +
Parameter -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: + Description -

- - + + + + + + +
-
-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
+      
BaseType + + The type being wrapped. + +
Policies + + A policy + class that supplies core functionality to the resulting iterator. A + detailed description can be found below. + +
Value + + The value_type of the resulting iterator, unless const. If + Value is const X the + value_type will be (non-const) X[1].
+ Default: + std::iterator_traits<BaseType>::value_type [2] + +
Reference + + The reference type of the resulting iterator, and in + particular, the result type of operator*().
+ Default: If Value is supplied, Value& is + used. Otherwise + std::iterator_traits<BaseType>::reference is used. + +
Pointer + + The pointer type of the resulting iterator, and in + particular, the result type of operator->().
+ Default: If Value was supplied, then Value*, + otherwise std::iterator_traits<BaseType>::pointer. + +
Category + + The iterator_category type for the resulting iterator.
+ Default: + std::iterator_traits<BaseType>::iterator_category + +
Distance + + The difference_type for the resulting iterator.
+ Default: + std::iterator_traits<BaseType>::difference_type +
+ +

The Policies Class

+ +

The main task in using iterator_adaptor is creating an + appropriate Policies class. The Policies class will + become the functional heart of the iterator adaptor, supplying the core + iterator operations that will determine how your new adaptor class will + behave. The iterator_adaptor template defines all of the operators + required of a Random Access + Iterator. Your Policies class must implement three, four, or + seven of the core iterator operations below depending on the iterator + categories you want it to support.
+
+ + + + + + + + + + + + + +
+ Core Iterator Operations
+ T: iterator type; p: object of type T; n: T::size_type; x: T::difference_type; p1, p2: iterators +
Operation + + Effects + + Implements Operations + + Required for Iterator Categories + +
dereference + + returns an element of the iterator's reference type + + *p, p[n] + + Input/ Output/ Forward/ Bidirectional/ + Random + Access + +
equal + + tests the iterator for equality + + p1 == p2, p1 != p2 + +
increment + + increments the iterator + + ++p, p++ + +
decrement + + decrements the iterator + + --p, p-- + + Bidirectional/ + Random + Access + +
less + + imposes a Strict Weak + Ordering relation on iterators + + + p1 < p2, + p1 <= p2, + p1 > p2, + p1 >= p2 + + Random + Access + +
distance + + measures the distance between iterators + + p1 - p2 + +
advance + + adds an integer offset to iterators + + +p + x, +x + p, +p += x, +p - x, +p -= x + +
+ +

The library also supplies a "trivial" policy class, + default_iterator_policies, which implements all seven of the core + operations in the usual way. If you wish to create an iterator adaptor that + only changes a few of the base type's behaviors, then you can derive your + new policy class from default_iterator_policies to avoid retyping + the usual behaviors. You should also look at + default_iterator_policies as the ``boilerplate'' for your own + policy classes, defining functions with the same interface. This is the + definition of default_iterator_policies:
+
+ +

+
+struct default_iterator_policies
 {
-  typedef ... iterator;
-  typedef ... const_iterator;
-};
-
- -

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

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

- -
-
-struct default_iterator_policies
-{
-  // required for a ForwardIterator
-  template <class Reference, class Iterator>
-  Reference dereference(type<Reference>, const Iterator& x) const
+  template <class Reference, class BaseType>
+  Reference dereference(type<Reference>, const BaseType& x) const
     { return *x; }
 
-  template <class Iterator>
-  static void increment(Iterator& x)
+  template <class BaseType>
+  static void increment(BaseType& x)
     { ++x; }
 
-  template <class Iterator1, class Iterator2>
-  bool equal(Iterator1& x, Iterator2& y) const
+  template <class BaseType1, class BaseType2>
+  bool equal(BaseType1& x, BaseType2& y) const
     { return x == y; }
 
-  // required for a BidirectionalIterator
-  template <class Iterator>
-  static void decrement(Iterator& x)
+  template <class BaseType>
+  static void decrement(BaseType& x)
     { --x; }
 
-  // required for a RandomAccessIterator
-  template <class Iterator, class DifferenceType>
-  static void advance(Iterator& x, DifferenceType n)
+  template <class BaseType, class DifferenceType>
+  static void advance(BaseType& x, DifferenceType n)
     { x += n; }
 
-  template <class Difference, class Iterator1, class Iterator2>
-  Difference distance(type<Difference>, Iterator1& x, Iterator2& y) const
+  template <class Difference, class BaseType1, class BaseType2>
+  Difference distance(type<Difference>, BaseType1& x, BaseType2& y) const
     { return y - x; }
 
-  template <class Iterator1, class Iterator2>
-  bool less(Iterator1& x, Iterator2& y) const
+  template <class BaseType1, class BaseType2>
+  bool less(BaseType1& x, BaseType2& y) const
     { return x < y; }
 };
-
+ + -

-The generated iterator adaptor types will have the following -constructors. +

Template member functions are used throughout + default_iterator_policies so that it can be employed with a wide + range of iterators. If we had used concrete types above, we'd have tied the + usefulness of default_iterator_policies to a particular range of + adapted iterators. If you follow the same pattern with your + Policies classes, you may achieve the same sort of reusability. -

- -
-
-iterator(const Iterator& i, const Policies& p = Policies())
+    

Additional Members

+ In addition to all of the member functions required of a Random Access + Iterator, the iterator_adaptor class template defines the + following members.
+
+ -const_iterator(const ConstIterator& i, const Policies& p = Policies()) -
+ + + + +
explicit iterator_adaptor(const Base&, const Policies& = + Policies()) +

+ Construct an adapted iterator from a base object and a policies + object. As this constructor is explicit, it does not + provide for implicit conversions from the Base type to + the iterator adaptor. -

The Iterator Adaptor Class

+
template <class B, class V, class R, class P>
+ iterator_adaptor(const + iterator_adaptor<B,Policies,V,R,P,Category,Distance>&)
+

+ This constructor allows for conversion from non-const to + constant adapted iterators. See below for more details.
+ Requires: B is convertible to Base. -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). +
base_type base() const; +

+ Return a copy of the base object. +
-

- -
-
-template <class Iterator,
-          class Policies = default_iterator_policies,
-          class Traits = std::iterator_traits<Iterator> >
-struct iterator_adaptor;
-
+

Example

+ +

It is often useful to automatically apply some function to the value + returned by dereferencing an iterator. The transform iterator makes it easy to create + an iterator adaptor which does just that. Here we will show how easy it is + to implement the transform iterator using the iterator_adaptor + template. + +

We want to be able to adapt a range of iterators and functions, so the + policies class will have a template parameter for the function type and it + will have a data member of that type. We know that the function takes one + argument and that we'll need to be able to deduce the result_type + of the function so we can use it for the adapted iterator's + value_type. AdaptableUnaryFunction + is the Concept + that fulfills those requirements. + +

To implement a transform iterator we will only change one of the base + iterator's behaviors, so the transform_iterator_policies class can + inherit the rest from default_iterator_policies. We will define + the dereference() member function, which is used to implement + operator*() of the adapted iterator. The implementation will + dereference the base iterator and apply the function object. The + type<Reference> parameter is used to convey the appropriate + return type. The complete code for transform_iterator_policies + is:
+
-

-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) { }
 
-    template <class Reference, class Iterator>
-    Reference dereference(type<Reference>, const Iterator& i) const
+    transform_iterator_policies(const AdaptableUnaryFunction& f)
+      : m_f(f) { }
+
+    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 template to + construct the transform iterator type. The nicest way to package the + construction of the transform iterator is to create a type generator. + The first template parameter to the generator will be the type of the + function object and the second will be the base iterator type. We use + iterator_adaptor to define the transform iterator type as a nested + typedef inside the transform_iterator_generator class. + Because the function may return by-value, we must limit the + iterator_category to Input Iterator, and + the iterator's reference type cannot be a true reference (the + standard allows this for input iterators), so in this case we can use few + of iterator_adaptor's default template arguments.
+
-

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

Here is an example that shows how to use a transform iterator to iterate + through a range of numbers, multiplying each of them by 2 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;
 }
-
+ + This output is: +

+2 4 6 8 10 12 14 16
+
+ +

Iterator Interactions

-

The Indirect Iterator Adaptors

+

C++ allows const and non-const pointers to interact in + the following intuitive ways: -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*. +

    +
  • a non-const pointer to T can be implicitly + converted to a const pointer to T. -To implement the indirect adaptors, we first create a policies class -which does a double-dereference in the dereference() method. +
  • const and non-const pointers to T can be + freely mixed in comparison expressions. -

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

  • const and non-const pointers to T can be + freely subtracted, in any order. +
-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. + Getting user-defined iterators to work together that way is nontrivial (see + here for an example of where + the C++ standard got it wrong), but iterator_adaptor can make it + easy. The rules are as follows: -

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

    +
  • Adapted iterators that share the same Policies, + Category, and Distance parameters are called + interoperable. -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. +
  • An adapted iterator can be implicitly converted to any other adapted + iterator with which it is interoperable, so long as the Base + type of the source iterator can be converted to the Base type of + the target iterator. -

    - -
    -
    -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;
    -};
    +      
  • Interoperable iterators can be freely mixed in comparison expressions + so long as the Policies class has equal (and, for + random access iterators, less) members that can accept both + Base types in either order. -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; -}; -
  • +

  • Interoperable iterators can be freely mixed in subtraction + expressions so long as the Policies class has a + distance member that can accept both Base types in + either order. +
+

Example

+ +

The Projection Iterator adaptor is similar to the transform iterator adaptor in that +its operator*() applies some function to the result of +dereferencing the base iterator and then returns the result. The +difference is that the function must return a reference to some +existing object (for example, a data member within the +value_type of the base iterator). -

The Projection Iterator Adaptors

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

- -
-
-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 implementation of projection iterator is as follows. First, the -policies class is the same as the transform iterator's policies class. - -

- -
-
-template <class AdaptableUnaryFunction>
-struct projection_iterator_policies : public default_iterator_policies
-{
-    projection_iterator_policies() { }
-    projection_iterator_policies(const AdaptableUnaryFunction& f) : m_f(f) { }
-
-    template <class Reference, class Iterator>
-    Reference dereference (type<Reference>, Iterator const& iter) const {
-        return m_f(*iter);
-    }
-
-    AdaptableUnaryFunction m_f;    
-};
-
- -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 {
+    

+The projection_iterator_pair_generator template + is a special two-type generator for mutable and constant versions of a + projection iterator. It is defined as follows: +

+
+template <class AdaptableUnaryFunction, class Iterator, class ConstIterator>
+struct projection_iterator_pair_generator {
     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;
+    typedef projection_iterator_policies<AdaptableUnaryFunction> policies;
+public:
+    typedef iterator_adaptor<Iterator,policies,value_type> iterator;
+    typedef iterator_adaptor<ConstIterator,policies,value_type,
+        const value_type&,const value_type*> const_iterator;
 };
+
+
-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; -}; -
+

It is assumed that the Iterator and ConstIterator arguments are corresponding mutable +and constant iterators.

    +
  • +Clearly, then, the +projection_iterator_pair_generator's iterator and +const_iterator are interoperable, since +they share the same Policies and since Category and +Distance as supplied by std::iterator_traits through the +default template parameters to +iterator_adaptor should be the same. -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. +
  • Since Iterator can presumably be converted to +ConstIterator, the projection iterator will be convertible to +the projection const_iterator. -

    - -
    -
    -template <class AdaptableUnaryFunction, class Iterator,
    -          class Traits = std::iterator_traits<Iterator>
    +
  • Since projection_iterator_policies implements only the +dereference operation, and inherits all other behaviors from default_iterator_policies, which has +fully-templatized equal, less, and distance +operations, the iterator and const_iterator can be freely +mixed in comparison and subtraction expressions. + + + +

    Challenge

    + +

    There is an unlimited number of ways 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. + +

    Concept Model

    + Depending on the Base and Policies template parameters, + an iterator_adaptor can be a Input Iterator, Forward + Iterator, Bidirectional + Iterator, or Random Access + Iterator. + +

    Declaration 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 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
    +struct iterator_adaptor
     {
    -  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; }
    +    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;
    +    typedef Policies policies_type;
    +
    +    iterator_adaptor();
    +    explicit iterator_adaptor(const Base&, const Policies& = Policies());
    +
    +    base_type base() const;
    +
    +    template <class B, class V, class R, class P>
    +    iterator_adaptor(
    +        const iterator_adaptor<B,Policies,V,R,P,Category,Distance>&);
    +
    +    reference operator*() const;
    +    operator_arrow_result_type operator->() const; [3]
    +    value_type operator[](difference_type n) const; [4]
    +
    +    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;
     };
    -
    -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. +template <class B, class P, class V, class R, class Ptr, + class C, class D1, class D2> +iterator_adaptor<B,P,V,R,Ptr,C,D1> +operator+(iterator_adaptor<B,P,V,R,Ptr,C,D1>, D2); -

    - -
    -
    -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;
    -};
    -
    +template <class B, class P, class V, class R, class Ptr, + class C, class D1, class D2> +iterator_adaptor<B,P,V,R,P,C,D1> +operator+(D2, iterator_adaptor<B,P,V,R,Ptr,C,D1> p); -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. +template <class B1, class B2, class P, 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>&); -

    - -
    -
    -class my_container {
    -  ...
    -  typedef ... iterator;
    -  typedef ... const_iterator;
    +template <class B1, class B2, class P, 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>&);
     
    -  typedef reverse_iterators<iterator, const_iterator> RevIters;
    -  typedef typename RevIters::iterator reverse_iterator;
    -  typedef typename RevIters::const_iterator const_reverse_iterator;
    -  ...
    -};
    -
    +// and similarly for operators !=, <, <=, >=, > + + +

    Notes

    + +

    [1] The standard specifies that the value_type + of const iterators to T (e.g. const T*) is + non-const T, while the pointer and + reference types for all Forward Iterators are + const T* and const T&, respectively. Stripping the + const-ness of Value allows you to easily + make a const iterator adaptor by supplying a const type + for Value, and allowing the defaults for the Pointer and + Reference parameters to take effect. Although compilers that don't + support partial specialization won't strip const for you, having a + const value_type is often harmless in practice. + +

    [2] If your compiler does not support partial + specialization and the base iterator is a builtin pointer type, you + will not be able to use the default for Value and will have to + specify this type explicitly. + +

    [3] 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 conforming + fashion, providing access to members of the objects pointed to by the + iterator. + +

    [4] The result type of operator[]() is + value_type instead of reference as might be expected. + There are two reasons for this choice. First, the C++ standard only + requires that the return type of an arbitrary Random Access + Iterator's operator[]be ``convertible to T'' (Table 76), so + when adapting an arbitrary base iterator we may not have a reference to + return. Second, and more importantly, for certain kinds of iterators, + returning a reference could cause serious memory problems due to the + reference being bound to a temporary object whose lifetime ends inside of + the operator[]. +


    + +

    Revised + 27 Feb 2001 -

    The Integer Range Class

    - -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 27 Nov 2000

    -

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

    +

    © Copyright Dave Abrahams and Jeremy Siek 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. + + + + + + + + + + +