.. Version 1.3 of this ReStructuredText document corresponds to
   n1530_, the paper accepted by the LWG for TR1.

.. Copyright David Abrahams, Jeremy Siek, and Thomas Witt 2003. 


.. parsed-literal::

  template <
      class Derived
    , class Value
    , class CategoryOrTraversal
    , class Reference  = Value&
    , class Difference = ptrdiff_t
  >
  class iterator_facade {
   public:
      typedef remove_const<Value>::type value_type;
      typedef Reference reference;
      typedef Value\* pointer;
      typedef Difference difference_type;
      typedef /* see below__ \*/ iterator_category;

      reference operator\*() const;
      /* see below__ \*/ operator->() const;
      /* see below__ \*/ operator[](difference_type n) const;
      Derived& operator++();
      Derived operator++(int);
      Derived& operator--();
      Derived operator--(int);
      Derived& operator+=(difference_type n);
      Derived& operator-=(difference_type n);
      Derived operator-(difference_type n) const;
   protected:
      typedef iterator_facade iterator_facade\_;
  };

  // Comparison operators
  template <class Dr1, class V1, class TC1, class R1, class D1,
            class Dr2, class V2, class TC2, class R2, class D2>
  typename enable_if_interoperable<Dr1,Dr2,bool>::type // exposition
  operator ==(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
              iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);

  template <class Dr1, class V1, class TC1, class R1, class D1,
            class Dr2, class V2, class TC2, class R2, class D2>
  typename enable_if_interoperable<Dr1,Dr2,bool>::type
  operator !=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
              iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);

  template <class Dr1, class V1, class TC1, class R1, class D1,
            class Dr2, class V2, class TC2, class R2, class D2>
  typename enable_if_interoperable<Dr1,Dr2,bool>::type
  operator <(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
             iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);

  template <class Dr1, class V1, class TC1, class R1, class D1,
            class Dr2, class V2, class TC2, class R2, class D2>
  typename enable_if_interoperable<Dr1,Dr2,bool>::type
  operator <=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
              iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);

  template <class Dr1, class V1, class TC1, class R1, class D1,
            class Dr2, class V2, class TC2, class R2, class D2>
  typename enable_if_interoperable<Dr1,Dr2,bool>::type
  operator >(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
             iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);

  template <class Dr1, class V1, class TC1, class R1, class D1,
            class Dr2, class V2, class TC2, class R2, class D2>
  typename enable_if_interoperable<Dr1,Dr2,bool>::type
  operator >=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
              iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);

  // Iterator difference
  template <class Dr1, class V1, class TC1, class R1, class D1,
            class Dr2, class V2, class TC2, class R2, class D2>
  /* see below__ \*/
  operator-(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
            iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);

  // Iterator addition
  template <class Dr, class V, class TC, class R, class D>
  Derived operator+ (iterator_facade<Dr,V,TC,R,D> const&,
                     typename Derived::difference_type n);

  template <class Dr, class V, class TC, class R, class D>
  Derived operator+ (typename Derived::difference_type n,
                     iterator_facade<Dr,V,TC,R,D> const&);

__ `iterator category`_

__ `operator arrow`_

__ brackets_

__ minus_

.. _`iterator category`:

The ``iterator_category`` member of ``iterator_facade`` is

.. parsed-literal::

  *iterator-category*\ (CategoryOrTraversal, value_type, reference)

where *iterator-category* is defined as follows:

.. include:: facade_iterator_category.rst

The ``enable_if_interoperable`` template used above is for exposition
purposes.  The member operators should only be in an overload set
provided the derived types ``Dr1`` and ``Dr2`` are interoperable, 
meaning that at least one of the types is convertible to the other.  The
``enable_if_interoperable`` approach uses SFINAE to take the operators
out of the overload set when the types are not interoperable.  
The operators should behave *as-if* ``enable_if_interoperable``
were defined to be::

  template <bool, typename> enable_if_interoperable_impl
  {};

  template <typename T> enable_if_interoperable_impl<true,T>
  { typedef T type; };

  template<typename Dr1, typename Dr2, typename T>
  struct enable_if_interoperable
    : enable_if_interoperable_impl<
          is_convertible<Dr1,Dr2>::value || is_convertible<Dr2,Dr1>::value
        , T
      >
  {};


``iterator_facade`` Requirements
--------------------------------

The following table describes the typical valid expressions on
``iterator_facade``\ 's ``Derived`` parameter, depending on the
iterator concept(s) it will model.  The operations in the first
column must be made accessible to member functions of class
``iterator_core_access``.  In addition,
``static_cast<Derived*>(iterator_facade*)`` shall be well-formed.

In the table below, ``F`` is ``iterator_facade<X,V,C,R,D>``, ``a`` is an
object of type ``X``, ``b`` and ``c`` are objects of type ``const X``,
``n`` is an object of ``F::difference_type``, ``y`` is a constant
object of a single pass iterator type interoperable with ``X``, and ``z``
is a constant object of a random access traversal iterator type
interoperable with ``X``.

.. _`core operations`:

.. topic:: ``iterator_facade`` Core Operations

   +--------------------+----------------------+-------------------------+---------------------------+
   |Expression          |Return Type           |Assertion/Note           |Used to implement Iterator |
   |                    |                      |                         |Concept(s)                 |
   +====================+======================+=========================+===========================+
   |``c.dereference()`` |``F::reference``      |                         |Readable Iterator, Writable|
   |                    |                      |                         |Iterator                   |
   +--------------------+----------------------+-------------------------+---------------------------+
   |``c.equal(y)``      |convertible to bool   |true iff ``c`` and ``y`` |Single Pass Iterator       |
   |                    |                      |refer to the same        |                           |
   |                    |                      |position.                |                           |
   +--------------------+----------------------+-------------------------+---------------------------+
   |``a.increment()``   |unused                |                         |Incrementable Iterator     |
   +--------------------+----------------------+-------------------------+---------------------------+
   |``a.decrement()``   |unused                |                         |Bidirectional Traversal    |
   |                    |                      |                         |Iterator                   |
   +--------------------+----------------------+-------------------------+---------------------------+
   |``a.advance(n)``    |unused                |                         |Random Access Traversal    |
   |                    |                      |                         |Iterator                   |
   +--------------------+----------------------+-------------------------+---------------------------+
   |``c.distance_to(z)``|convertible to        |equivalent to            |Random Access Traversal    |
   |                    |``F::difference_type``|``distance(c, X(z))``.   |Iterator                   |
   +--------------------+----------------------+-------------------------+---------------------------+



``iterator_facade`` operations
------------------------------

The operations in this section are described in terms of operations on
the core interface of ``Derived`` which may be inaccessible
(i.e. private).  The implementation should access these operations
through member functions of class ``iterator_core_access``.

``reference operator*() const;``

:Returns: ``static_cast<Derived const*>(this)->dereference()``

``operator->() const;`` (see below__)

__ `operator arrow`_

:Returns: If ``reference`` is a reference type, an object
  of type ``pointer`` equal to::

    &static_cast<Derived const*>(this)->dereference()

  Otherwise returns an object of unspecified type such that, 
  ``(*static_cast<Derived const*>(this))->m`` is equivalent to ``(w = **static_cast<Derived const*>(this),
  w.m)`` for some temporary object ``w`` of type ``value_type``.

.. _brackets:

*unspecified* ``operator[](difference_type n) const;``

:Returns: an object convertible to ``value_type``. For constant
     objects ``v`` of type ``value_type``, and ``n`` of type
     ``difference_type``, ``(*this)[n] = v`` is equivalent to
     ``*(*this + n) = v``, and ``static_cast<value_type
     const&>((*this)[n])`` is equivalent to
     ``static_cast<value_type const&>(*(*this + n))``



``Derived& operator++();``

:Effects: 

  ::

    static_cast<Derived*>(this)->increment();
    return *static_cast<Derived*>(this);

``Derived operator++(int);``

:Effects:

  ::

    Derived tmp(static_cast<Derived const*>(this));
    ++*this;
    return tmp;


``Derived& operator--();``

:Effects:

   ::

      static_cast<Derived*>(this)->decrement();
      return *static_cast<Derived*>(this);


``Derived operator--(int);``

:Effects:

  ::

    Derived tmp(static_cast<Derived const*>(this));
    --*this;
    return tmp;


``Derived& operator+=(difference_type n);``

:Effects:

  ::

      static_cast<Derived*>(this)->advance(n);
      return *static_cast<Derived*>(this);


``Derived& operator-=(difference_type n);``

:Effects:
 
  ::

      static_cast<Derived*>(this)->advance(-n);
      return *static_cast<Derived*>(this);


``Derived operator-(difference_type n) const;``

:Effects:

  ::

    Derived tmp(static_cast<Derived const*>(this));
    return tmp -= n;

::

  template <class Dr, class V, class TC, class R, class D>
  Derived operator+ (iterator_facade<Dr,V,TC,R,D> const&,
                     typename Derived::difference_type n);

  template <class Dr, class V, class TC, class R, class D>
  Derived operator+ (typename Derived::difference_type n,
                     iterator_facade<Dr,V,TC,R,D> const&);

:Effects:

  ::

    Derived tmp(static_cast<Derived const*>(this));
    return tmp += n;


::

  template <class Dr1, class V1, class TC1, class R1, class D1,
            class Dr2, class V2, class TC2, class R2, class D2>
  typename enable_if_interoperable<Dr1,Dr2,bool>::type
  operator ==(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
              iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);

:Returns: 
  if ``is_convertible<Dr2,Dr1>::value``

  then 
    ``((Dr1 const&)lhs).equal((Dr2 const&)rhs)``.

  Otherwise, 
    ``((Dr2 const&)rhs).equal((Dr1 const&)lhs)``.

::

  template <class Dr1, class V1, class TC1, class R1, class D1,
            class Dr2, class V2, class TC2, class R2, class D2>
  typename enable_if_interoperable<Dr1,Dr2,bool>::type
  operator !=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
              iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);

:Returns: 
  if ``is_convertible<Dr2,Dr1>::value``

  then 
    ``!((Dr1 const&)lhs).equal((Dr2 const&)rhs)``.

  Otherwise, 
    ``!((Dr2 const&)rhs).equal((Dr1 const&)lhs)``.

::

  template <class Dr1, class V1, class TC1, class R1, class D1,
            class Dr2, class V2, class TC2, class R2, class D2>
  typename enable_if_interoperable<Dr1,Dr2,bool>::type
  operator <(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
             iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);

:Returns: 
  if ``is_convertible<Dr2,Dr1>::value``

  then 
    ``((Dr1 const&)lhs).distance_to((Dr2 const&)rhs) < 0``.

  Otherwise, 
    ``((Dr2 const&)rhs).distance_to((Dr1 const&)lhs) > 0``.

::

  template <class Dr1, class V1, class TC1, class R1, class D1,
            class Dr2, class V2, class TC2, class R2, class D2>
  typename enable_if_interoperable<Dr1,Dr2,bool>::type
  operator <=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
              iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);

:Returns: 
  if ``is_convertible<Dr2,Dr1>::value``

  then 
    ``((Dr1 const&)lhs).distance_to((Dr2 const&)rhs) <= 0``.

  Otherwise, 
    ``((Dr2 const&)rhs).distance_to((Dr1 const&)lhs) >= 0``.

::

  template <class Dr1, class V1, class TC1, class R1, class D1,
            class Dr2, class V2, class TC2, class R2, class D2>
  typename enable_if_interoperable<Dr1,Dr2,bool>::type
  operator >(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
             iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);

:Returns: 
  if ``is_convertible<Dr2,Dr1>::value``

  then 
    ``((Dr1 const&)lhs).distance_to((Dr2 const&)rhs) > 0``.

  Otherwise, 
    ``((Dr2 const&)rhs).distance_to((Dr1 const&)lhs) < 0``.


::

  template <class Dr1, class V1, class TC1, class R1, class D1,
            class Dr2, class V2, class TC2, class R2, class D2>
  typename enable_if_interoperable<Dr1,Dr2,bool>::type
  operator >=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
              iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);

:Returns: 
  if ``is_convertible<Dr2,Dr1>::value``

  then 
    ``((Dr1 const&)lhs).distance_to((Dr2 const&)rhs) >= 0``.

  Otherwise, 
    ``((Dr2 const&)rhs).distance_to((Dr1 const&)lhs) <= 0``.

.. _minus:

::

  template <class Dr1, class V1, class TC1, class R1, class D1,
            class Dr2, class V2, class TC2, class R2, class D2>
  typename enable_if_interoperable<Dr1,Dr2,difference>::type
  operator -(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
             iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);

:Return Type: 
  if ``is_convertible<Dr2,Dr1>::value``

   then 
    ``difference`` shall be
    ``iterator_traits<Dr1>::difference_type``.

   Otherwise 
    ``difference`` shall be ``iterator_traits<Dr2>::difference_type``

:Returns: 
  if ``is_convertible<Dr2,Dr1>::value``

  then 
    ``-((Dr1 const&)lhs).distance_to((Dr2 const&)rhs)``.

  Otherwise, 
    ``((Dr2 const&)rhs).distance_to((Dr1 const&)lhs)``.
