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 ]