Boost logo

Boost :

From: David Abrahams (abrahams_at_[hidden])
Date: 2000-11-24 15:59:05


From: "Jeremy Siek" <jsiek_at_[hidden]>

>
> Upon updating the test code for indirect iterators I realized there's a
> problem with the way we are currently getting the inner const iterator
> type. (for T**, I'm using "inner" to mean T* and "outer" to mean T**)
>
> Currently we are just trying to add a "const" qualification to the inner
> iterator (iterator_traits<T**>::value_type) to get the inner const
> iterator (const iterator_traits<T**>::value_type). I think this is wrong
> for a couple reasons. First, I think adding the const there gives you a
> const iterator instead of an immutable iterator (the const needs to apply
> to the thing pointed at).

I think John has been trying to get us to see that for months.

> Second, if the inner iterator types in question
> are not real pointers like T*, then there is no way to deduce the
> const_iterator type from the iterator type.

Oh, yeah; I think that /is/ a problem.

> Given this, I think the interface for indirect iterator needs to change so
> that both inner iterator types are explicitly provided by the user.

I think you may be right. The other tack would be to try to add the 'const'
to T, thus:
deque<const T>::iterator... so, obviously, that won't work for so many
reasons ;-(

I think there's an interesting parallel between what we're doing with
iterator_adaptors and what a container does. It would be instructive to try
to generalize the layers between the value_type and the iterator, and
describe the const/non-const relationships...someday. I'm just grasping at a
vague idea here, but wouldn't one want:

deque<const T>::iterator == deque<T>::const_iterator == (const
deque<T>)::iterator

in some sense?

> Also, the interface currently asks the user for both the const and
> non-const version of the outer iterator. This is not necessary since
> we really don't care whether the outer iterator is mutable or not.
>
> So here's what I think indirect_iterators should look like:
>
> template <class IndirectIterator, // Mutable or Immutable, doesn't matter
> class Iterator, // Mutable
> class ConstIterator, // Immutable
> class IndirectTraits = std::iterator_traits<IndirectIterator>,
> class Traits = std::iterator_traits<Iterator>,
> class ConstTraits = std::iterator_traits<ConstIterator>
> >
> struct indirect_iterators
> {
> typedef typename Traits::value_type ValueType;
> typedef iterator_adaptors<IndirectIterator, IndirectIterator,
> indirect_traits<IndirectIterator, IndirectTraits, Traits>,
> indirect_traits<IndirectIterator, IndirectTraits, ConstTraits>,
> indirect_iterator_policies
> > Adaptors;
> typedef typename Adaptors::iterator iterator;
> typedef typename Adaptors::const_iterator const_iterator;
> };

I'm far enough away from the inner workings now that I find the above highly
confusing. Especailly incantations like: "indirect_traits<IndirectIterator,
IndirectTraits, Traits>". If you'd like to add some commentary, I'm sure it
would help other readers/maintainers. Otherwise, I am prepared to trust that
you and John have the situation well in-hand.

> Here is John's example again, updated to use the new interface.
> If you get rid of the #if 0 you'll see that the const iterator
> correctly prevents writing to the immutable value.

Excellent!

-Dave


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk