From 8c3ed628dc2f44caeab191db448f240e4c05492e Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Thu, 15 Jan 2004 04:31:50 +0000 Subject: [PATCH] Handled the rest of my issues. [SVN r21752] --- doc/facade-and-adaptor.html | 468 ++++++++++++++++++++++++------------ doc/iter-issue-list.rst | 45 +--- doc/iterator_facade.html | 336 ++++++++++++++++++-------- doc/iterator_facade_ref.rst | 219 ++++++++++++----- 4 files changed, 726 insertions(+), 342 deletions(-) diff --git a/doc/facade-and-adaptor.html b/doc/facade-and-adaptor.html index d910380..f91c8a7 100755 --- a/doc/facade-and-adaptor.html +++ b/doc/facade-and-adaptor.html @@ -56,83 +56,84 @@ by adapting other iterators.

Table of Contents

-

Motivation

+

Motivation

Iterators play an important role in modern C++ programming. The iterator is the central abstraction of the algorithms of the Standard Library, allowing algorithms to be re-used in in a wide variety of @@ -227,15 +228,15 @@ applies some user-specified function during the dereference of the iterator.

-

Impact on the Standard

+

Impact on the Standard

This proposal is purely an addition to the C++ standard library. However, note that this proposal relies on the proposal for New Iterator Concepts.

-

Design

+

Design

-

Iterator Concepts

+

Iterator Concepts

This proposal is formulated in terms of the new iterator concepts as proposed in n1550, since user-defined and especially adapted iterators suffer from the well known categorization problems that are @@ -245,7 +246,7 @@ is a direct mapping between new and old categories. This proposal could be reformulated using this mapping if n1550 was not accepted.

-

Interoperability

+

Interoperability

The question of iterator interoperability is poorly addressed in the current standard. There are currently two defect reports that are concerned with interoperability issues.

@@ -265,7 +266,7 @@ fixes the issues raised in 280. It provides the desired interoperability without introducing unwanted overloads.

-

iterator_adaptor public operations

+

iterator_adaptor public operations

iterator_adaptor();

@@ -1133,7 +1281,7 @@ expression involving Derived i
-

iterator_adaptor protected member functions

+

iterator_adaptor protected member functions

Base const& base_reference() const;

@@ -1154,7 +1302,7 @@ expression involving Derived i
-

iterator_adaptor private member functions

+

iterator_adaptor private member functions

typename iterator_adaptor::reference dereference() const;

@@ -1223,7 +1371,7 @@ typename iterator_adaptor::difference_type distance_to(
-

Specialized adaptors [lib.iterator.special.adaptors]

+

Specialized adaptors [lib.iterator.special.adaptors]

The enable_if_convertible<X,Y>::type expression used in this section is for exposition purposes. The converting constructors for specialized adaptors should be only be in an overload set provided @@ -1252,7 +1400,7 @@ take the constructor out of the overload set when the types are not implicitly convertible. ]

-

Indirect iterator

+

Indirect iterator

indirect_iterator adapts an iterator by applying an extra dereference inside of operator*(). For example, this iterator adaptor makes it possible to view a container of pointers @@ -1262,7 +1410,7 @@ auxiliary traits, pointee and provide support for underlying iterators whose value_type is not an iterator.

-

Class template pointee

+

Class template pointee

@@ -1306,7 +1454,7 @@ else
-

Class template indirect_iterator

+

Class template indirect_iterator

 template <
     class Iterator
@@ -1409,17 +1557,17 @@ else
     typedef Difference difference_type;
 
 if (CategoryOrTraversal is use_default)
-    typedef iterator-category(
+    typedef iterator-category(
         iterator_traversal<Iterator>::type,``reference``,``value_type``
     ) iterator_category;
 else
-    typedef iterator-category(
+    typedef iterator-category(
         CategoryOrTraversal,``reference``,``value_type``
     ) iterator_category;
 
-

indirect_iterator requirements

+

indirect_iterator requirements

The expression *v, where v is an object of iterator_traits<Iterator>::value_type, shall be valid expression and convertible to reference. Iterator shall @@ -1433,7 +1581,7 @@ parameter is not use_default, deducing the default for the value_type member.]

-

indirect_iterator models

+

indirect_iterator models

In addition to the concepts indicated by iterator_category and by iterator_traversal<indirect_iterator>::type, a specialization of indirect_iterator models the following @@ -1454,7 +1602,7 @@ expression (where t is an obje interoperable with Y.

-

indirect_iterator operations

+

indirect_iterator operations

In addition to the operations required by the concepts described above, specializations of indirect_iterator provide the following operations.

@@ -1546,11 +1694,11 @@ indirect_iterator(
-

Reverse iterator

+

Reverse iterator

The reverse iterator adaptor iterates through the adapted iterator range in the opposite direction.

-

Class template reverse_iterator

+

Class template reverse_iterator

 template <class Iterator>
 class reverse_iterator
@@ -1587,11 +1735,11 @@ Lvalue Iterator, then iterator_categoryinput_iterator_tag.

-

reverse_iterator requirements

+

reverse_iterator requirements

Iterator must be a model of Bidirectional Traversal Iterator.

-

reverse_iterator models

+

reverse_iterator models

A specialization of reverse_iterator models the same iterator traversal and iterator access concepts modeled by its Iterator argument. In addition, it may model old iterator concepts @@ -1630,7 +1778,7 @@ Random Access Traversal Iterator Y.

-

reverse_iterator operations

+

reverse_iterator operations

In addition to the operations required by the concepts modeled by reverse_iterator, reverse_iterator provides the following operations.

@@ -1720,12 +1868,12 @@ return *--tmp;
-

Transform iterator

+

Transform iterator

The transform iterator adapts an iterator by modifying the operator* to apply a function object to the result of dereferencing the iterator and returning the result.

-

Class template transform_iterator

+

Class template transform_iterator

 template <class UnaryFunction,
@@ -1778,7 +1926,7 @@ model Readable Lvalue Iterator then iterat
 convertible to input_iterator_tag.

-

transform_iterator requirements

+

transform_iterator requirements

The type UnaryFunction must be Assignable, Copy Constructible, and the expression f(*i) must be valid where f is an object of type UnaryFunction, i is an object of type Iterator, and @@ -1787,7 +1935,7 @@ where the type of f(*i) must b

The argument Iterator shall model Readable Iterator.

-

transform_iterator models

+

transform_iterator models

The resulting transform_iterator models the most refined of the following options that is also modeled by Iterator.

@@ -1834,7 +1982,7 @@ mutable iterator (as defined in the old iterator requirements).

interoperable with Y.

-

transform_iterator operations

+

transform_iterator operations

In addition to the operations required by the concepts modeled by transform_iterator, transform_iterator provides the following operations.

@@ -1927,7 +2075,7 @@ transform_iterator(
-

Filter iterator

+

Filter iterator

The filter iterator adaptor creates a view of an iterator range in which some elements of the range are skipped. A predicate function object controls which elements are skipped. When the predicate is @@ -1939,7 +2087,7 @@ underlying range. A filter iterator is therefore constructed with pair of iterators indicating the range of elements in the unfiltered sequence to be traversed.

-

Class template filter_iterator

+

Class template filter_iterator

@@ -1980,7 +2128,7 @@ Iterator then iterator_categorystd::input_iterator_tag
.

-

filter_iterator requirements

+

filter_iterator requirements

The Predicate argument must be Assignable, Copy Constructible, and the expression p(x) must be valid where p is an object of type Predicate, x is an object of type @@ -1991,7 +2139,7 @@ Iterator and Single Pass Iterator or it shall meet the requirements of Input Iterator.

-

filter_iterator models

+

filter_iterator models

The concepts that filter_iterator models are dependent on which concepts the Iterator argument models, as specified in the following tables.

@@ -2062,7 +2210,7 @@ following tables.

if and only if X is interoperable with Y.

-

filter_iterator operations

+

filter_iterator operations

In addition to those operations required by the concepts that filter_iterator models, filter_iterator provides the following operations.

@@ -2173,12 +2321,12 @@ or m_pred(*m_iter) -

Counting iterator

+

Counting iterator

counting_iterator adapts an object by adding an operator* that returns the current value of the object. All other iterator operations are forwarded to the adapted object.

-

Class template counting_iterator

+

Class template counting_iterator

 template <
     class Incrementable
@@ -2214,10 +2362,10 @@ algorithm:

if (CategoryOrTraversal is not use_default) return CategoryOrTraversal else if (numeric_limits<Incrementable>::is_specialized) - return iterator-category( + return iterator-category( random_access_traversal_tag, Incrementable, const Incrementable&) else - return iterator-category( + return iterator-category( iterator_traversal<Incrementable>::type, Incrementable, const Incrementable&)
@@ -2226,7 +2374,7 @@ of operator- and a default Incrementable is a numeric type.]

-

counting_iterator requirements

+

counting_iterator requirements

The Incrementable argument shall be Copy Constructible and Assignable.

If iterator_category is convertible to forward_iterator_tag or forward_traversal_tag, the following must be well-formed:

@@ -2252,7 +2400,7 @@ i < j;
-

counting_iterator models

+

counting_iterator models

Specializations of counting_iterator model Readable Lvalue Iterator. In addition, they model the concepts corresponding to the iterator tags to which their iterator_category is convertible. @@ -2268,7 +2416,7 @@ concepts modeled by IncrementableY.

-

counting_iterator operations

+

counting_iterator operations

In addition to the operations required by the concepts modeled by counting_iterator, counting_iterator provides the following operations.

@@ -2344,7 +2492,7 @@ operations.

-

Function output iterator

+

Function output iterator

The function output iterator adaptor makes it easier to create custom output iterators. The adaptor takes a unary function and creates a model of Output Iterator. Each item assigned to the output iterator is @@ -2353,7 +2501,7 @@ iterator is that creating a conforming output iterator is non-trivial, particularly because the proper implementation usually requires a proxy object.

-

Class template function_output_iterator

+

Class template function_output_iterator

 template <class UnaryFunction>
 class function_output_iterator {
@@ -2375,16 +2523,16 @@ private:
 
-

function_output_iterator requirements

+

function_output_iterator requirements

UnaryFunction must be Assignable and Copy Constructible.

-

function_output_iterator models

+

function_output_iterator models

function_output_iterator is a model of the Writable and Incrementable Iterator concepts.

-

function_output_iterator operations

+

function_output_iterator operations

explicit function_output_iterator(const UnaryFunction& f = UnaryFunction());

diff --git a/doc/iter-issue-list.rst b/doc/iter-issue-list.rst index e1d51dd..2f249f1 100644 --- a/doc/iter-issue-list.rst +++ b/doc/iter-issue-list.rst @@ -62,8 +62,8 @@ to be members or non-members. or non-members. -9.3 enable_if_interoperable needs standardese (Dave) -==================================================== +9.3 enable_if_interoperable needs standardese +============================================= :Submitter: Pete Becker :Status: New @@ -81,11 +81,7 @@ N1541 48 behavior of these functions is undefined if the two types aren't interoperable. - **Needs work** (Dave) I'm not happy with Pete's proposal. - - (thw) Pete is correct with regard to the requirement. Removing the - interoperable stuff would be an error. By all means we don't want - undefined behaviour here. + **Needs diffs** (fixed in text). 9.4 enable_if_convertible unspecified, conflicts with requires ============================================================== @@ -526,16 +522,12 @@ like "when using iterator_facade to define an iterator class Iter, the class Ite from a specialization of iterator_facade whose first template argument is Iter." That's a bit awkward, but at the moment I don't see a better way of phrasing it. -:Proposed resolution: **Needs work** (Dave) Reword. - 01/01/04 thw - The wording is certainly insufficient. AFAICS there are two issues. - First the issue addressed by Pete i.e. specifying the requirements for - implementing a valid iterator. The other issue I can see is that we - need to be able to unambigously cast the iterator_facade specialisation - to Iter. +:Proposed resolution: Add: In addition, + ``static_cast(iterator_facade*)`` shall be + well-formed. -9.22 return type of Iterator difference for iterator facade (Dave) -================================================================== +9.22 return type of Iterator difference for iterator facade +=========================================================== :Submitter: Pete Becker :Status: New @@ -554,20 +546,7 @@ to the other type, then the subtraction is okay. Seems like the return type should then be the type that was converted to. Is that right? -:Proposed resolution: - Change the return type from :: - - typename enable_if_interoperable::type - - to :: - - typename enable_if_interoperable::type - - 01/01/04 thw - Almost, the return type should be the difference_type of the - converted to iterator. BTW how does std::distance handle - different but interoperable iterator types? - +:Proposed resolution: **Needs diffs** (fixed in text) 9.23 Iterator_facade: minor wording Issue ========================================= @@ -818,8 +797,8 @@ c++std-lib-12333: this issue for Readable Iterator and Lvalue Iterator. -9.34 iterator_facade free functions unspecified (Dave) -====================================================== +9.34 iterator_facade free functions unspecified +=============================================== :Submitter: Pete Becker :Status: New @@ -834,7 +813,7 @@ c++std-lib-12562: iterator_facade and an argument of type difference_type has no specification. -:Proposed resolution: **Needs work** Add the missing specifications. +:Proposed resolution: **Needs diffs** Added the missing specifications. 9.35 iterator_facade: too many equals? diff --git a/doc/iterator_facade.html b/doc/iterator_facade.html index 6a2bbe9..df4c831 100644 --- a/doc/iterator_facade.html +++ b/doc/iterator_facade.html @@ -45,43 +45,44 @@ and associated types, to be supplied by a derived iterator class.
-

Overview

+

Overview

@@ -662,7 +810,7 @@ example of a linked list of polymorphic objects. This example was inspired by a posting by Keith Macdonald on the Boost-Users mailing list.

-

The Problem

+

The Problem

Say we've written a polymorphic linked list node base class:

 # include <iostream>
@@ -724,7 +872,7 @@ inline std::ostream& operator<<(std::ostream& s, node_base const&a
 lists.

-

A Basic Iterator Using iterator_facade

+

A Basic Iterator Using iterator_facade

We will construct a node_iterator class using inheritance from iterator_facade to implement most of the iterator's operations.

@@ -738,24 +886,24 @@ class node_iterator
 };
 
-

Template Arguments for iterator_facade

+

Template Arguments for iterator_facade

iterator_facade has several template parameters, so we must decide what types to use for the arguments. The parameters are Derived, Value, CategoryOrTraversal, Reference, and Difference.

-

Derived

+

Derived

Because iterator_facade is meant to be used with the CRTP -[Cop95] the first parameter is the iterator class name itself, +[Cop95] the first parameter is the iterator class name itself, node_iterator.

-

Value

+

Value

The Value parameter determines the node_iterator's value_type. In this case, we are iterating over node_base objects, so Value will be node_base.

-

CategoryOrTraversal

+

CategoryOrTraversal

Now we have to determine which iterator traversal concept our node_iterator is going to model. Singly-linked lists only have forward links, so our iterator can't can't be a bidirectional @@ -763,19 +911,19 @@ traversal iterator. Our iterator should be able to make multiple passes over the same linked list (unlike, say, an istream_iterator which consumes the stream it traverses), so it must be a forward traversal iterator. Therefore, we'll pass -boost::forward_traversal_tag in this position 1.

+boost::forward_traversal_tag in this position 1.

-
[1]iterator_facade also supports old-style category +
[1]iterator_facade also supports old-style category tags, so we could have passed std::forward_iterator_tag here; either way, the resulting iterator's iterator_category will end up being std::forward_iterator_tag.
-
-

Reference

+
+

Reference

The Reference argument becomes the type returned by node_iterator's dereference operation, and will also be the same as std::iterator_traits<node_iterator>::reference. The @@ -784,7 +932,7 @@ library's default for this parameter is Va type, we can omit this argument, or pass use_default.

-

Difference

+

Difference

The Difference argument determines how the distance between two node_iterators will be measured and will also be the same as std::iterator_traits<node_iterator>::difference_type. @@ -811,14 +959,14 @@ class node_iterator

-

Constructors and Data Members

+

Constructors and Data Members

Next we need to decide how to represent the iterator's position. This representation will take the form of data members, so we'll also need to write constructors to initialize them. The node_iterator's position is quite naturally represented using a pointer to a node_base. We'll need a constructor to build an iterator from a node_base*, and a default constructor to -satisfy the forward traversal iterator requirements 2. +satisfy the forward traversal iterator requirements 2. Our node_iterator then becomes:

 # include "node.hpp"
@@ -848,7 +996,7 @@ class node_iterator
 
-
@@ -856,7 +1004,7 @@ default constructor to leave m_node
 
[2]Technically, the C++ standard places almost no +
[2]Technically, the C++ standard places almost no requirements on a default-constructed iterator, so if we were really concerned with efficiency, we could've written the default constructor to leave m_node uninitialized.
-

Implementing the Core Operations

+

Implementing the Core Operations

The last step is to implement the core operations required by the concepts we want our iterator to model. Referring to the table, we can see that the first three rows are applicable @@ -907,7 +1055,7 @@ iterator! For a working example of its use, see -

A constant node_iterator

+

A constant node_iterator

-

Interoperability

+

Interoperability

Our const_node_iterator works perfectly well on its own, but taken together with node_iterator it doesn't quite meet expectations. For example, we'd like to be able to pass a @@ -1020,7 +1168,7 @@ compare them for equality.

This expected ability to use two different iterator types together is known as interoperability. Achieving interoperability in our case is as simple as templatizing the equal function and -adding a templatized converting constructor 3 4:

+adding a templatized converting constructor 3 4:

 template <class Value>
 class node_iter
@@ -1065,14 +1213,14 @@ typedef impl::node_iterator<node_base const> node_const_iterator;
 
-
[3]If you're using an older compiler and it can't handle +
[3]If you're using an older compiler and it can't handle this example, see the example code for workarounds.
- @@ -1081,7 +1229,7 @@ traversal iterator, we'd have had to templatize its iterators here.

-

Telling the Truth

+

Telling the Truth

Now node_iterator and node_const_iterator behave exactly as you'd expect... almost. We can compare them and we can convert in one direction: from node_iterator to node_const_iterator. @@ -1119,7 +1267,7 @@ appropriate:

-

Wrap Up

+

Wrap Up

This concludes our iterator_facade tutorial, but before you stop reading we urge you to take a look at iterator_adaptor. There's another way to approach writing these iterators which might diff --git a/doc/iterator_facade_ref.rst b/doc/iterator_facade_ref.rst index 51ff2ac..47fe684 100644 --- a/doc/iterator_facade_ref.rst +++ b/doc/iterator_facade_ref.rst @@ -18,7 +18,7 @@ public: typedef remove_const::type value_type; typedef Reference reference; - typedef Value* pointer; + typedef Value\* pointer; typedef Difference difference_type; typedef /* see below__ \*/ iterator_category; @@ -37,57 +37,55 @@ // Comparison operators template - typename enable_if_interoperable::type // exposition - operator ==(iterator_facade const& lhs, - iterator_facade const& rhs); + typename enable_if_interoperable::type // exposition + operator ==(iterator_facade const& lhs, + iterator_facade const& rhs); template - typename enable_if_interoperable::type - operator !=(iterator_facade const& lhs, - iterator_facade const& rhs); + typename enable_if_interoperable::type + operator !=(iterator_facade const& lhs, + iterator_facade const& rhs); template - typename enable_if_interoperable::type - operator <(iterator_facade const& lhs, - iterator_facade const& rhs); + typename enable_if_interoperable::type + operator <(iterator_facade const& lhs, + iterator_facade const& rhs); template - typename enable_if_interoperable::type - operator <=(iterator_facade const& lhs, - iterator_facade const& rhs); + typename enable_if_interoperable::type + operator <=(iterator_facade const& lhs, + iterator_facade const& rhs); template - typename enable_if_interoperable::type - operator >(iterator_facade const& lhs, - iterator_facade const& rhs); + typename enable_if_interoperable::type + operator >(iterator_facade const& lhs, + iterator_facade const& rhs); template - typename enable_if_interoperable::type - operator >=(iterator_facade const& lhs, - iterator_facade const& rhs); - - template - typename enable_if_interoperable::type - operator >=(iterator_facade const& lhs, - iterator_facade const& rhs); + typename enable_if_interoperable::type + operator >=(iterator_facade const& lhs, + iterator_facade const& rhs); // Iterator difference template - typename enable_if_interoperable::type - operator -(iterator_facade const& lhs, - iterator_facade const& rhs); + /* see below__ \*/ + operator-(iterator_facade const& lhs, + iterator_facade const& rhs); // Iterator addition - template - Derived operator+ (iterator_facade const&, - typename Derived::difference_type n) + template + Derived operator+ (iterator_facade const&, + typename Derived::difference_type n); + + template + Derived operator+ (typename Derived::difference_type n, + iterator_facade const&); __ `iterator category`_ @@ -95,6 +93,8 @@ __ `operator arrow`_ __ brackets_ +__ minus_ + .. _`iterator category`: The ``iterator_category`` member of ``iterator_facade`` is @@ -138,7 +138,8 @@ 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``. +``iterator_core_access``. In addition, +``static_cast(iterator_facade*)`` shall be well-formed. In the table below, ``F`` is ``iterator_facade``, ``a`` is an object of type ``X``, ``b`` and ``c`` are objects of type ``const X``, @@ -151,27 +152,28 @@ interoperable with ``X``. .. 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`` refer to the|Single Pass Iterator | - | | |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 ``distance(c, X(z))``. |Random Access Traversal | - | |``F::difference_type``| |Iterator | - +--------------------+----------------------+-------------------------------------+---------------------------+ + +--------------------+----------------------+-------------------------+---------------------------+ + |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 | + +--------------------+----------------------+-------------------------+---------------------------+ @@ -280,8 +282,115 @@ __ `operator arrow`_ :: - Derived tmp(static_cast(this)); - return tmp -= n; + Derived tmp(static_cast(this)); + return tmp -= n; + +:: + + template + Derived operator+ (iterator_facade const&, + typename Derived::difference_type n); + + template + Derived operator+ (typename Derived::difference_type n, + iterator_facade const&); + +:Effects: + + :: + + Derived tmp(static_cast(this)); + return tmp += n; + +``iterator_facade`` interoperability +------------------------------------ + +:: + + template + typename enable_if_interoperable::type + operator ==(iterator_facade const& lhs, + iterator_facade const& rhs); + +:Returns: if ``is_convertible::value``, then + ``lhs.equal(rhs)``. Otherwise, ``rhs.equal(lhs)``. + +:: + + template + typename enable_if_interoperable::type + operator !=(iterator_facade const& lhs, + iterator_facade const& rhs); + +:Returns: if ``is_convertible::value``, then + ``!lhs.equal(rhs)``. Otherwise, ``!rhs.equal(lhs)``. + +:: + + template + typename enable_if_interoperable::type + operator <(iterator_facade const& lhs, + iterator_facade const& rhs); + +:Returns: if ``is_convertible::value``, then + ``lhs.distance_to(rhs) < 0``. Otherwise, ``rhs.distance_to(lhs) > + 0``. + +:: + + template + typename enable_if_interoperable::type + operator <=(iterator_facade const& lhs, + iterator_facade const& rhs); + +:Returns: if ``is_convertible::value``, then + ``lhs.distance_to(rhs) <= 0``. Otherwise, ``rhs.distance_to(lhs) + >= 0``. + +:: + + template + typename enable_if_interoperable::type + operator >(iterator_facade const& lhs, + iterator_facade const& rhs); + +:Returns: if ``is_convertible::value``, then + ``lhs.distance_to(rhs) > 0``. Otherwise, + ``rhs.distance_to(lhs) < 0``. +:: + template + typename enable_if_interoperable::type + operator >=(iterator_facade const& lhs, + iterator_facade const& rhs); + +:Returns: if ``is_convertible::value``, then + ``lhs.distance_to(rhs) >= 0``. Otherwise, + ``rhs.distance_to(lhs) <= 0``. + +.. _minus: + +:: + + template + typename enable_if_interoperable::type + operator -(iterator_facade const& lhs, + iterator_facade const& rhs); + +:Return Type: if ``is_convertible::value``, then ``difference_type`` shall be + ``iterator_traits::difference_type``. Otherwise, + ``difference_type`` shall be + ``iterator_traits::difference_type``. + +:Returns: if ``is_convertible::value``, then + ``-lhs.distance_to(rhs)``. Otherwise, + ``-rhs.distance_to(lhs)``.

[4]If node_iterator had been a random access +
[4]If node_iterator had been a random access traversal iterator, we'd have had to templatize its distance_to function as well.