Boost logo

Boost :

From: Richard Smith (richard_at_[hidden])
Date: 2006-07-12 09:27:47


The Standard's table of InputIterator requirements
(table 72 in section 24.1) says that, amongst other things,
an InputIterator must support the following two expressions:

  *a Convertible to T, the iterator's value_type

  a->m Equivalent to (*a).m

The same language is present in the "New Iterator Concepts",
N1550, documentation in the definition of ReadableIterator.

In particular, InputIterators are allowed to, and often do,
have operator* returning by value:

  template <typename T> class my_iterator {
  public:
    typedef T value_type;
    T operator*() const;
    // ...
  };

Because it is legal to call non-const member functions on
temporary objects, it is legal to call non-const member
functions on the value returned from operator*:

  struct foo {
    void non_const();
  };

  my_iterator<foo> i;
  (*i).non_const();

My reading of Table 72 documentation suggests that this
means that for my_iterator<foo> to be a Readable Iterator,
it must also be legal to write:

  i->non_const();

If so, this means that operator-> should return T* instead
of T const* (possibly via a proxy class). In the current
implementation of boost::iterator_facade, operator-> returns
a proxy that acts as a T const*:

    template <class T>
    struct operator_arrow_proxy
    {
        operator_arrow_proxy(T const* px) : m_value(*px) {}
        const T* operator->() const { return &m_value; }
        operator const T*() const { return &m_value; }
        T m_value;
    };

Is there a reason not to change this to have operator->
returning a T*? That would seem closer to the defintion of
an InputIterator.

(I supposed that if operator* returns by const value, it
would be necessary to resurrect the constness in the proxy,
but assuming the iterator's reference typedef is also a
const-qualified value, this should be easy enough.)

I had a look at the current concept-based iterator proposal,
N2039, to see whether that shed any light on this and it
also seems to require this behaviour from an InputIterator.
It formal concept only requires operator->'s return to be
convertible to T const* (which T*, or a proxy to T*, is):

  concept InputIterator<typename X> {
    where /*...*/ Convertible<pointer, value_type const*>;
    pointer operator->(X);
    //
  }

And in it's definition of operator->, it requires (*a).m to
be well-formed and then defines a->m to be equivalent to it.

Have I misunderstood some aspect of this, or does the
Standard really all require that a generic input iterator
adaptor, such as boost::iterator_adaptor (and by
impliciation boost::iterator_facade) should support this?

--
Richard Smith

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