$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
From: jsiek_at_[hidden]
Date: 1999-11-28 02:03:13
Dave Abrahams writes:
 > This is some great work.
 > I would like to see the following direction considered:
 > 
 > 1. Rename fundamental components and integrate with operators.hpp:
 > 
 > postfix_inc_operator<T> -> incrementable<T>
 > postfix_dec_operator<T> -> decrementable<T>
 > member_operator<T> -> dereferenceable<T>
and how about
random_access_operator -> randomly_accessible<T>
 > [I'd have done this myself but for some reason I didn't realize these
 > operators didn't have to be members]
Yeah, I found that in the standard not too long ago when I was
wondering why inheriting the member postfix inc operator wasn't working.
 > 2. Make use of addable<T, U> and subtractable<T, U> from operators.hpp
Righto... it really is a good feeling to delete code :)
 > 3. Find some way to automatically define the appropriate iterator tag based
 > on the helper base class being used (note that your test example sets up the
 > wrong iterator tag!) One approach would be to simply add (optional?)
 > template parameters that fill the other roles of the std::iterator<>
 > template. I'd love to hear of a better way.
Hmmm, I don't see a better way to do that. It's a little bit of a
sticky issue, but requiring the 4 associated types as arguments to the
helpers does not seem too bad to me.
Here's what iterator_ops.hpp looks like with the above suggestions:
//  (C) Copyright Jeremy Siek 1999. Permission to copy, use, modify,
//  sell and distribute this software is granted provided this
//  copyright notice appears in all copies. This software is provided
//  "as is" without express or implied warranty, and with no claim as
//  to its suitability for any purpose.
#ifndef BOOST_ITERATOR_OPS_HPP
#define BOOST_ITERATOR_OPS_HPP
#include <iterator>
#include <boost/operators.hpp>
#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE
namespace boost
{
#endif
template <class T>
struct incrementable
{
  friend T operator++(T& x, int)
  {
    T tmp(x);
    ++x;
    return tmp;
  }
};
  
template <class T>
struct decrementable
{
  friend T operator--(T& x, int)
  {
    T tmp(x);
    --x;
    return tmp;                      
  }
};
template <class T, class V>
struct dereferenceable
{
  V* operator->() const { 
    return &*static_cast<const T&>(*this); 
  }
};
template <class T, class D, class R>
class randomly_accessible
{
public:
  R operator[](D n) const {
    return *(static_cast<const T&>(*this) + n);
  }
};
template <class T, class V, class D, class P, class R>
struct forward_iterator_helper :
  public equality_comparable<T,T>,
  public incrementable<T>,
  public dereferenceable<T,V>,
  public std::iterator<std::forward_iterator_tag, V, D, P, R> { };
template <class T, class V, class D, class P, class R>
struct bidirectional_iterator_helper :
  public equality_comparable<T,T>,
  public incrementable<T>,
  public decrementable<T>,
  public dereferenceable<T,V>,
  public std::iterator<std::bidirectional_iterator_tag, V, D, P, R> { };
template <class T, class V, class D, class P, class R>
struct random_access_iterator_helper :
  public equality_comparable<T,T>,
  public less_than_comparable<T,T>,
  public incrementable<T>,
  public decrementable<T>,
  public dereferenceable<T,V>,
  public addable<T,D>,
  public subtractable<T,D>,
  public randomly_accessible<T,D,R>,
  public std::iterator<std::random_access_iterator_tag, V, D, P, R> { };
#ifndef BOOST_NO_OPERATORS_IN_NAMESPACE
} /* namespace boost */
#else
namespace boost {
  using ::incrementable;
  using ::decrementable;
  using ::dereferenceable;
  using ::randomly_accessible;
  using ::forward_iterator_helper;
  using ::bidirectional_iterator_helper;
  using ::random_access_iterator_helper;
}
#endif
#endif /* BOOST_ITERATOR_OPS_HPP */
//  (C) Copyright Jeremy Siek 1999. Permission to copy, use, modify,
//  sell and distribute this software is granted provided this
//  copyright notice appears in all copies. This software is provided
//  "as is" without express or implied warranty, and with no claim as
//  to its suitability for any purpose.
#include <string>
#include <iostream>
#include <iterator>
#include <boost/array.hpp>
#include <mtl/iterator_ops.hpp>
using namespace std;
using namespace boost;
template <class T>
struct test_iter
  : public boost::random_access_iterator_helper<test_iter<T>, T, int, T*, T&>
{
  typedef test_iter self;
  typedef typename self::reference Reference;
  typedef typename self::difference_type Distance;
public:
  test_iter(T* i) : _i(i) { }
  test_iter(const self& x) : _i(x._i) { }
  self& operator=(const self& x) { _i = x._i; return *this; }
  Reference operator*() const { return *_i; }
  self& operator++() { ++_i; return *this; }
  self& operator--() { --_i; return *this; }
  self& operator+=(Distance n) { _i += n; return *this; }
  self& operator-=(Distance n) { _i -= n; return *this; }
  friend bool operator==(const self& x, const self& y) { return x._i == y._i; }
  friend bool operator<(const self& x, const self& y) { return x._i < y._i; }
protected:
  T* _i;
};
int
main()
{
  string array[] = { "apple", "orange", "pear", "peach", "grape", "plum"  };
  test_iter<string> i = begin(array), ie = end(array);
  // test i++
  while (i != ie)
    cout << *i++ << " ";
  cout << endl;
  i = begin(array);
  // test i--
  while (ie != i) {
    ie--;
    cout << *ie << " ";
  }
  cout << endl;
  ie = end(array);
  // test i->m
  while (i != ie) {
    cout << i->size() << " ";
    ++i;
  }
  cout << endl;
  i = begin(array);
  // test i + n
  while (i < ie) {
    cout << *i << " ";
    i = i + 2;
  }
  cout << endl;
  i = begin(array);
  // test n + i
  while (i < ie) {
    cout << *i << " ";
    i = 2 + i;
  }
  cout << endl;
  i = begin(array);
  // test i - n
  while (ie > i) {
    ie = ie - 2;
    cout << *ie << " ";
  }
  cout << endl;
  ie = end(array);
  for (int j = 0; j < size(array) ; ++j)
    cout << i[j] << " ";
  cout << endl;
  return 0;
}