Topic: Comments on Library Active Issue #179: Comparison of const_iterators to iterators


Author: Stephen Cleary <scleary@jerviswebb.com>
Date: 2000/07/11
Raw View
Just two comments and a proposed adaption to the resolution:

1) What about operator-?  We could let operator- work for const/non-
const mix, too.

2) The reverse_iterator adapter (as currently written) does not
preserve these operations.  Consider the code:

  #include <iterator>

  bool func(std::reverse_iterator<int *> a,
      std::reverse_iterator<const int *> b)
  { return (a == b); }

reverse_iterator may be fixed by changing all the comparision operator
definitions (and operator-, if desired) to have an extra template
parameter, the underlying iterator of the second parameter.  AFAIK,
this introduces no ambiguities, and solves the problem above.

Sample code for a new reverse_iterator, and test code showing its use
and the current std::reverse_iterator failings follows this message.

I propose that we allow operator- to support a const/non-const mix, and
extend reverse_iterator to preserve these operational mappings.

 -Steve

----- Sample Code Follows -----

#include <iterator>

namespace my {

template <typename Iterator>
class reverse_iterator: public std::iterator<
    typename std::iterator_traits<Iterator>::iterator_category,
    typename std::iterator_traits<Iterator>::value_type,
    typename std::iterator_traits<Iterator>::difference_type,
    typename std::iterator_traits<Iterator>::pointer,
    typename std::iterator_traits<Iterator>::reference>
{
  protected:
    Iterator current;

  public:
    typedef Iterator iterator_type;
    typedef typename std::iterator_traits<Iterator>::difference_type
        difference_type;
    typedef typename std::iterator_traits<Iterator>::reference
        reference;
    typedef typename std::iterator_traits<Iterator>::pointer
        pointer;

    reverse_iterator() { }
    explicit reverse_iterator(Iterator x):current(x) { }
    template <typename U>
    reverse_iterator(const reverse_iterator<U> & x)
    :current(x.base()) { }

    Iterator base() const { return current; }
    reference operator*() const
    { Iterator tmp = current; return *--tmp; }
    pointer operator->() const { return &**this; }

    reverse_iterator & operator++() { --current; return *this; }
    reverse_iterator operator++(int)
    { reverse_iterator tmp = *this; --*this; return tmp; }
    reverse_iterator & operator--() { ++current; return *this; }
    reverse_iterator operator--(int)
    { reverse_iterator tmp = *this; ++*this; return tmp; }

    reverse_iterator operator+(difference_type n) const
    { return reverse_iterator(current - n); }
    reverse_iterator & operator+=(difference_type n)
    { current -= n; return *this; }
    reverse_iterator operator-(difference_type n) const
    { return reverse_iterator(current + n); }
    reverse_iterator & operator-=(difference_type n)
    { current += n; return *this; }
    reference operator[](difference_type n) const
    { return current[-n-1]; }

#if 0
    // Friend, non-templated
    //  Results in ambiguity errors
    friend bool operator==(const reverse_iterator & a,
        const reverse_iterator & b)
    { return (a.base() == b.base()); }
#endif
#if 0
    // Member, non-templated:
    //  Tries to convert const to non-const
    bool operator==(const reverse_iterator & b) const
    { return (current == b.base()); }
#endif
#if 0
    // Friend, templated:
    //  I think this should work; doesn't under BCB4
    template <typename U>
    friend bool operator==(const reverse_iterator & a,
        const reverse_iterator<U> & b)
    { return (a.base() == b.base()); }
#endif
#if 0
    // Member, templated:
    //  This works
    template <typename U>
    bool operator==(const reverse_iterator<U> & b) const
    { return (current == b.base()); }
#endif

    friend reverse_iterator operator+(difference_type n,
        const reverse_iterator & x)
    { return reverse_iterator(current - n); }
};
#if 0
// Global, non-templated:
//  Template deduction won't find UDC
template <typename Iterator>
bool operator==(const reverse_iterator<Iterator> & a,
    const reverse_iterator<Iterator> & b)
{ return (a.base() == b.base()); }
#endif
#if 1
// Global, templated:
//  This works
template <typename Iterator, typename U>
bool operator==(const reverse_iterator<Iterator> & a,
    const reverse_iterator<U> & b)
{ return (a.base() == b.base()); }
#endif

// All other ops are shown as global, templated:
template <typename Iterator, typename U>
bool operator!=(const reverse_iterator<Iterator> & a,
    const reverse_iterator<U> & b)
{ return (a.base() != b.base()); }
template <typename Iterator, typename U>
bool operator<(const reverse_iterator<Iterator> & a,
    const reverse_iterator<U> & b)
{ return (a.base() > b.base()); }
template <typename Iterator, typename U>
bool operator>(const reverse_iterator<Iterator> & a,
    const reverse_iterator<U> & b)
{ return (a.base() < b.base()); }
template <typename Iterator, typename U>
bool operator<=(const reverse_iterator<Iterator> & a,
    const reverse_iterator<U> & other)
{ return (a.base() >= b.base()); }
template <typename Iterator, typename U>
bool operator>=(const reverse_iterator<Iterator> & a,
    const reverse_iterator<U> & other)
{ return (a.base() <= b.base()); }

template <typename Iterator, typename U>
typename reverse_iterator<Iterator>::difference_type
operator-(const reverse_iterator<Iterator> & a,
    const reverse_iterator<U> & other)
{ return (b.base() - a.base()); }

} // namespace my

int main(void)
{
  int array[10];

  //
  // Normal iterators: Issue 179 permits this with iterators
  //  other than pointers
  //

  typedef int * iterator;
  typedef const int * const_iterator;

  iterator begin = array;
  const_iterator const_end = array + 10;

  if (begin == const_end || const_end == begin)
    ; // OK

  //
  // The replacement reverse_iterator maintains this requirement
  //

  typedef my::reverse_iterator<iterator> my_reverse_iterator;
  typedef my::reverse_iterator<const_iterator>
      my_const_reverse_iterator;

  my_const_reverse_iterator my_const_rbegin(const_end);
  my_reverse_iterator my_rend(begin);

  if (my_const_rbegin == my_rend || my_rend == my_const_rbegin)
    ; // OK

  //
  // The std::reverse_iterator does not
  //

  typedef std::reverse_iterator<iterator> std_reverse_iterator;
  typedef std::reverse_iterator<const_iterator>
      std_const_reverse_iterator;

  std_const_reverse_iterator std_const_rbegin(const_end);
  std_reverse_iterator std_rend(begin);

  // Uncomment the following line to see
  //  how std::reverse_iterator fails
//  if (std_const_rbegin == std_rend || std_rend == std_const_rbegin)
    ; // Not OK!

  return 0;
}


Sent via Deja.com http://www.deja.com/
Before you buy.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]