diff --git a/iterator_adaptor_test.cpp b/iterator_adaptor_test.cpp index 03f44aa..8e8d0de 100644 --- a/iterator_adaptor_test.cpp +++ b/iterator_adaptor_test.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -97,6 +98,8 @@ typedef std::deque storage; typedef std::deque pointer_deque; typedef std::set iterator_set; +template struct foo; + int main() { @@ -105,17 +108,54 @@ main() const int N = sizeof(array)/sizeof(dummyT); // sanity check, if this doesn't pass the test is buggy - boost::random_access_iterator_test(array,N,array); + boost::random_access_iterator_test(array, N, array); +#if 0 // Check that the policy concept checks and the default policy // implementation match up. boost::function_requires< boost::RandomAccessIteratorPoliciesConcept< - boost::default_iterator_policies, int*, + boost::default_iterator_policies, + boost::iterator_adaptor, boost::iterator > >(); + // Test the named parameters + { + // Test computation of defaults + typedef boost::iterator_adaptor > Iter1; + BOOST_STATIC_ASSERT((boost::is_same::value_type, int>::value)); + BOOST_STATIC_ASSERT((boost::is_same::reference, int&>::value)); + BOOST_STATIC_ASSERT((boost::is_same::pointer, int*>::value)); + BOOST_STATIC_ASSERT((boost::is_same::difference_type, std::ptrdiff_t>::value)); + BOOST_STATIC_ASSERT((boost::is_same::iterator_category, std::random_access_iterator_tag>::value)); + } + { + // Test computation of default when the Value is const + typedef boost::iterator_adaptor > Iter1; + BOOST_STATIC_ASSERT((boost::is_same::value_type, int>::value)); + BOOST_STATIC_ASSERT((boost::is_same::reference, const int&>::value)); + BOOST_STATIC_ASSERT((boost::is_same::pointer, const int*>::value)); + } + { + // Test with no defaults + typedef boost::iterator_adaptor, + boost::pointer_is, + boost::value_type_is, + boost::iterator_category_is, + boost::difference_type_is + > Iter1; + BOOST_STATIC_ASSERT((boost::is_same::value_type, char>::value)); + BOOST_STATIC_ASSERT((boost::is_same::reference, long>::value)); + BOOST_STATIC_ASSERT((boost::is_same::pointer, float>::value)); + BOOST_STATIC_ASSERT((boost::is_same::difference_type, int>::value)); + BOOST_STATIC_ASSERT((boost::is_same::iterator_category, std::input_iterator_tag>::value)); + } + // Test the iterator_adaptor { boost::iterator_adaptor i(array); @@ -173,7 +213,7 @@ main() typedef boost::reverse_iterator_generator::type const_reverse_iterator; @@ -306,12 +346,12 @@ main() #else typedef boost::iterator_adaptor, boost::default_iterator_policies, - boost::iterator_traits_generator - ::value_type - ::reference - ::pointer - ::iterator_category - ::difference_type > adaptor_type; + boost::reference_is, + boost::pointer_is , + boost::iterator_category_is, + boost::value_type_is, + boost::difference_type_is + > adaptor_type; #endif adaptor_type i(forward_iter); int zero = 0; @@ -330,6 +370,7 @@ main() if (zero) // don't do this, just make sure it compiles assert((*i).m_x == i->foo()); } +#endif std::cout << "test successful " << std::endl; return 0; } diff --git a/iterator_adaptors.htm b/iterator_adaptors.htm index aa3c42a..2b6c7a5 100644 --- a/iterator_adaptors.htm +++ b/iterator_adaptors.htm @@ -26,6 +26,37 @@ "../../more/generic_programming.html#adaptors">adaptors which apply specific useful behaviors to arbitrary base iterators. +

Backward Compatibility Note

+ +

The library's interface has changed since it was first released, breaking + backward compatibility: + +

    + +
  1. Policies classes now operate on instances of the + whole iterator_adaptor object, rather than just operating on the + Base object. This change not only gives the policies class access + to both members of a pair of interacting iterators, but also eliminates the + need for the ugly type<Reference> and + type<Difference> parameters to various policy functions. + +
  2. The Named Template Parameter + interface has been made simpler, easier to use, and compatible with more + compilers. + +
+ +

Other Documentation

+ +

``Policy Adaptors and the Boost Iterator + Adaptor Library'' is a technical paper describing this library and the + powerful design pattern on which it is based. It was presented at the C++ Template Workshop at OOPSLA + 2001; the slides from the talk are available here. Please note that while the slides + incorporate the minor interface changes described in the previous section, + the paper does not. +

Table of Contents

    @@ -183,7 +214,7 @@ struct iterator_adaptor; particular, the result type of operator*().
    Default: If Value is supplied, Value& is used. Otherwise - std::iterator_traits<BaseType>::reference is used. + std::iterator_traits<BaseType>::reference is used. [7] Pointer @@ -191,7 +222,7 @@ struct iterator_adaptor; 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. + otherwise std::iterator_traits<BaseType>::pointer. [7] Category @@ -385,40 +416,40 @@ typedef iterator_adaptor<foo_iterator, foo_policies,
     struct default_iterator_policies
     {
    -  template <class BaseType>
    -  void initialize(BaseType&)
    -    { }
    +    // Some of these members were defined static, but Borland got confused
    +    // and thought they were non-const. Also, Sun C++ does not like static
    +    // function templates.
     
    -  template <class Reference, class BaseType>
    -  Reference dereference(type<Reference>, const BaseType& x) const
    -    { return *x; }
    +    template <class Base>
    +    void initialize(Base&)
    +        { }
     
    -  template <class BaseType>
    -  void increment(BaseType& x)
    -    { ++x; }
    +    template <class IteratorAdaptor>
    +    typename IteratorAdaptor::reference dereference(const IteratorAdaptor& x) const
    +        { return *x.base(); }
     
    -  template <class BaseType1, class BaseType2>
    -  bool equal(const BaseType1& x, const BaseType2& y) const
    -    { return x == y; }
    +    template <class IteratorAdaptor>
    +    void increment(IteratorAdaptor& x)
    +        { ++x.base(); }
     
    -  template <class BaseType>
    -  void decrement(BaseType& x)
    -    { --x; }
    +    template <class IteratorAdaptor>
    +    void decrement(IteratorAdaptor& x)
    +        { --x.base(); }
     
    -  template <class BaseType, class DifferenceType>
    -  void advance(BaseType& x, DifferenceType n)
    -    { x += n; }
    +    template <class IteratorAdaptor, class DifferenceType>
    +    void advance(IteratorAdaptor& x, DifferenceType n)
    +        { x.base() += n; }
     
    -  template <class Difference, class BaseType1, class BaseType2>
    -  Difference distance(type<Difference>, const BaseType1& x, const BaseType2& y) const
    -    { return y - x; }
    +    template <class IteratorAdaptor1, class IteratorAdaptor2>
    +    typename IteratorAdaptor1::difference_type
    +    distance(const IteratorAdaptor1& x, const IteratorAdaptor2& y) const
    +        { return y.base() - x.base(); }
     
    -  template <class BaseType1, class BaseType2>
    -  bool less(const BaseType1& x, const BaseType2& y) const
    -    { return x < y; }
    +    template <class IteratorAdaptor1, class IteratorAdaptor2>
    +    bool equal(const IteratorAdaptor1& x, const IteratorAdaptor2& y) const
    +        { return x.base() == y.base(); }
     };
    -
    - +

    Template member functions are used throughout default_iterator_policies so that it can be employed with a wide @@ -451,7 +482,7 @@ struct default_iterator_policies iterator_adaptor(const iterator_adaptor<B,Policies,V,R,P,Category,Distance>&)

    - This constructor allows for conversion from non-const to + This constructor allows for conversion from mutable to constant adapted iterators. See below for more details.
    Requires: B is convertible to Base. @@ -483,34 +514,31 @@ struct default_iterator_policies

    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 + 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:
    + dereference the base iterator and apply the function object. The complete + code for transform_iterator_policies is:

    - -

    -
    -  template <class AdaptableUnaryFunction>
    -  struct transform_iterator_policies : public default_iterator_policies
    -  {
    +
    +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 BaseIterator>
    -    Reference dereference(type<Reference>, const BaseIterator& i) const
    -      { return m_f(*i); }
    +        : m_f(f) { }
    +    
    +    template <class IteratorAdaptor>
    +    typename IteratorAdaptor::reference
    +    dereference(const IteratorAdaptor& iter) const
    +        { return m_f(*iter.base()); }
     
         AdaptableUnaryFunction m_f;
    -  };
    -
    -
    +}; + +

    The next step is to use the iterator_adaptor template to construct the transform iterator type. The nicest way to package the @@ -546,7 +574,7 @@ public:

    As a finishing touch, we will create an object generator - for the transform iterator. This is a function that makes it more + for the transform iterator. Our object generator makes it more convenient to create a transform iterator.

    @@ -785,12 +813,12 @@ bool operator==(const iterator_adaptor<B1,P,V1,R1,P1,C,D>&, 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. + const-ness of Value allows you to easily make a constant + iterator 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 @@ -856,6 +884,14 @@ bool operator==(const iterator_adaptor<B1,P,V1,R1,P1,C,D>&, *x = i; +

    [7] + If you are using a compiler that does not have a version of + std::iterator_traits that works for pointers (i.e., if your + compiler does not support partial specialization) then if the + Base type is a const pointer, then the correct defaults + for the reference and pointer types can not be + deduced. You must specify these types explicitly. +


    Revised