Boost logo

Boost :

From: David Abrahams (david.abrahams_at_[hidden])
Date: 2001-10-02 16:35:13

----- Original Message -----
From: <michel.andre_at_[hidden]>

> > template <class Difference, class BaseType1, class BaseType2>
> > Difference distance(type<Difference>, const BaseType1& x, const
> > BaseType2& y) const {}
> >
> > As I understand it, the "BaseType1/2" is misleading, because the
> > parameter is not the base iterator, it's the adapted iterator. Do I
> > understand correctly? I hope so, because it would be impossible to
> > make this work for adaptors that have internal state otherwise.
> It seems from the source code that it is the Base or underlying
> iterator thats sent into to the policy class.
> I'm wrestling with a similar problem and the iterator_adaptors i want
> to keep all state in the "begin()" iterator and have the "end()" with
> just a flag saying endIterator and this means to be able to determine
> equality i need the policy objects for both rhs and lhs in the equal
> method of the policy class.
> template <class Iterator1, class Iterator2>
> bool equal(const Iterator1& x, const Iterator2& y) const

This is a problem which occurred to me long after Jeremy started storing a
policies object in the iterator adaptor so he could keep extra state. Hey,

> The reason for my design is that the iterator generated by begin
> contains both the start and the end of the iteration and in some
> cases even a pointer to the container of the elements to iterate over.
> Is there some solution to this problem? Or do i have to "adapt" the
> base iterator with my state (using eg inheritance) and then use the
> iterator_adapter to adapt my "adaption" to get it to work?

If inheritance works for you (remember, you can't inherit from a pointer),
then go for it. That seems like the easiest approach. Otherwise, consider
std::pair<IteratorType,StateData> or the equivalent.

We should probably think about changing the design. I think a
backwards-compatible change is possible, but I don't think the extra cruft
implied is desirable:

struct default_iterator_policies
    // 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 Base>
    void initialize(Base&)
        { }

    // The "type<Reference>" parameter is a portable mechanism for
    // the iterator_adaptor class to tell this member function what
    // the Reference type is, which is needed for the return type.
    template <class Reference, class Base>
    Reference dereference(type<Reference>, const Base& x) const
        { return *x; }

    template <class Iterator>
    void increment2(Iterator& x)
        { x.policies().increment(x.iter()); }

    template <class Base>
    void increment(Base& x)
        { ++x; }

    template <class Iterator>
    void decrement2(Iterator& x)
        { x.policies().decrement(x.iter()); }

    template <class Base>
    void decrement(Base& x)
        { --x; }

    template <class Iterator, class DifferenceType>
    void advance2(Iterator& x, DifferenceType n)
        { x.policies().advance(x.iter(), n); }

    template <class Base, class DifferenceType>
    void advance(Base& x, DifferenceType n)
        { x += n; }

You get the idea. Now you can redefine difference2 instead of difference to
get the behavior you want. Hmm, have I just invented a new kind of
compile-time virtual function here? ;-)

Anyway, I'd like to discuss with the group whether backwards-compatibility
is paramount. Should we maintain the status quo, crufty-up the design and
the documentation to maintain backward-compatibility, provide a transition
path using #ifdefs, or something else?

  David Abrahams, C++ library designer for hire

        C++ Booster (
          email: david.abrahams_at_[hidden]

Boost list run by bdawes at, gregod at, cpdaniel at, john at