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
@@ -985,7 +1215,7 @@ return tmp -= n;
template <
class Iterator
@@ -1319,7 +1549,7 @@ satisfies the requirements of the concepts modeled by the indirect
iterator as specified in the models section.
The Iterator argument shall meet the requirements of Readable
Iterator. The CategoryOrTraversal argument shall be one of the
standard iterator tags or use_default. If CategoryOrTraversal
@@ -1335,7 +1565,7 @@ is not use_default, as implied
default for the value_type member.
If CategoryOrTraversal is a standard iterator tag,
indirect_iterator is a model of the iterator concept corresponding
to the tag, otherwise indirect_iterator satisfies the requirements
@@ -1349,7 +1579,7 @@ the Iterator argument.
The reverse iterator adaptor flips the direction of a base iterator's
motion. Invoking operator++() moves the base iterator backward and
invoking operator--() moves the base iterator forward.
The base Iterator must be a model of Bidirectional Traversal
-Iterator. The resulting reverse_iterator will be a model of the
-most refined standard traversal and access concepts that are modeled
-by Iterator.
reverse_iterator models Bidirectional Traversal Iterator and
+Readable Iterator. In addition, reverse_iterator models the same
+standard iterator access concepts that the Iterator
+argument models.
The transform iterator adapts an iterator by applying some function
object to the result of dereferencing the iterator. In other words,
the operator* of the transform iterator first dereferences the
base iterator, passes the result of this to the function object, and
then returns the result.
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
where the type of f(*i) must be
result_of<UnaryFunction(iterator_traits<Iterator>::reference)>::type.
-
The type Iterator must at least model Readable Iterator. The
-resulting transform_iterator models the most refined of the
+
The type Iterator must at least model Readable Iterator.
The resulting transform_iterator models the most refined of the
following options that is also modeled by Iterator.
@@ -1550,8 +1800,8 @@ concept that is modeled by Iteratorresult_of<UnaryFunction(iterator_traits<Iterator>::reference)>::type.
The value_type is remove_cv<remove_reference<reference>>::type.
The filter iterator adaptor creates a view of an iterator range in
which some elements of the range are skipped over. A predicate
function object controls which elements are skipped. When the
@@ -1625,7 +1891,7 @@ of the underlying range. Therefore the constructor of the filter
iterator takes two iterator parameters: the position for the filtered
iterator and the end of the range.
template <class Predicate, class Iterator>
class filter_iterator
@@ -1647,15 +1913,17 @@ class filter_iterator
);
Predicate predicate() const;
Iterator end() const;
+ reference operator*() const;
+ filter_iterator& operator++();
};
-
The iterator_category is a type convertible to the tags
+
The iterator_category member is a type convertible to the tags
corresponding to each standard concept modeled by filter_iterator,
as described in the models section.
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
@@ -1666,7 +1934,7 @@ Iterator and Single Pass Iterator or it shall meet the requirements of
Input Iterator.
In addition to those operations required by the concepts that
filter_iterator models, filter_iterator provides the following
operations.
@@ -1781,8 +2025,8 @@ whose end is a default constru
-
Returns:
A filter_iterator at position x that filters according
-to predicate f and that will not increment past end.
+
Returns:
A filter_iterator at the first position in the range [x,end)
+such that f(*this->base())==true or else at position end.
@@ -1793,6 +2037,10 @@ to predicate f and that will n
Requires:
Predicate must be Default Constructible.
+
Returns:
A filter_iterator at the first position in the range [x,end)
+such that f(*this->base())==true, where f is a default
+constructed Predicate, or else at position end.
+
Returns:
A filter_iterator at position x that filters
according to a default constructed Predicate
and that will not increment past end.
@@ -1812,7 +2060,8 @@ filter_iterator(
Requires:
OtherIterator is implicitly convertible to Iterator.
-
Returns:
A copy of iterator t.
+
Returns:
A filter iterator at the same position as iterator t
+whose predicate and end are copies of t.predicate and t.end() .
@@ -1834,43 +2083,50 @@ filter_iterator(
+
referenceoperator*()const;
+
+
+
+
+
Returns:
*(this->base())
+
+
+
+
filter_iterator&operator++();
+
+
+
+
+
Effects:
Increments *this and then continues to
+increment *this until either this->base()==this->end()
+or f(**this)==true.
The counting iterator adaptor implements dereference by returning a
-reference to the base object. The other operations are implemented by
-the base m_iterator, as per the inheritance from
-iterator_adaptor.
The Incrementable type must be Default Constructible, Copy
Constructible, and Assignable. The default distance is
-an implementation defined signed integegral type.
-
The resulting counting_iterator models Readable Lvalue Iterator.
+an implementation defined signed integral type.
+
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
@@ -1949,7 +2235,7 @@ iterator is that creating a conforming output iterator is non-trivial,
particularly because the proper implementation usually requires a
proxy object.
The UnaryFunction must be Assignable, Copy Constructible, and the
expression f(x) must be valid, where f is an object of type
UnaryFunction and x is an object of a type accepted by f.
@@ -1985,7 +2271,7 @@ The resulting function_output_iterator
In this section we'll walk through the implementation of a few
iterators using iterator_facade, based around the simple
example of a linked list of polymorphic objects.
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
+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.
iterator_facade also supports old-style category
+tags, so we could've passed std::forward_iterator_tag here;
+either way, the resulting iterator's iterator_category will
+end up being std::forward_iterator_tag.
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
+library's default for this parameter is Value&; since
+node_base& is a good choice for the iterator's reference
+type, we can omit this argument, or pass use_default.
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.
+The library's default for Difference is std::ptrdiff_t, an
+appropriate type for measuring the distance between any two
+addresses in memory, and one that works for almost any iterator,
+so we can omit this argument, too.
+
The declaration of node_iterator will therefore look something
+like:
+
+# include "node.hpp"
+# include <boost/iterator/iterator_facade.hpp>
+
+class node_iterator
+ : public boost::iterator_facade<
+ node_iterator
+ , node_base
+ , boost::forward_traversal_tag
+ >
+{
+ ...
+};
+
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.
+Our node_iterator then becomes:
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.
We therefore need to supply dereference,
+equal, and increment members. We don't want these members
+to become part of node_iterator's public interface, so we can
+make them private and grant friendship to
+boost::iterator_core_access, a "back-door" that
+iterator_facade uses to get access to the core operations:
The term mutable iterator means an iterator through which
+the object it references (its "referent") can be modified. A
+constant iterator is one which doesn't allow modification of
+its referent.
+
The words constant and mutable don't refer to the ability to
+modify the iterator itself. For example, an intconst* is a
+non-constconstant iterator, which can be incremented
+but doesn't allow modification of its referent, and int*
+const is a constmutable iterator, which cannot be
+modified but which allows modification of its referent.
+
Confusing? We agree, but those are the standard terms. It
+probably doesn't help much that a container's constant iterator
+is called const_iterator.
+
+
Now, our node_iterator gives clients access to both node's print(std::ostream&)const member function, but also its
+mutating double_me() member. If we wanted to build a
+constantnode_iterator, we'd only have to make three
+changes:
The C++ standard requires an iterator's value_typenot be
+const-qualified, so iterator_facade strips the
+const from its Value parameter in order to produce the
+iterator's value_type. Making the Value argument
+const provides a useful hint to iterator_facade that the
+iterator is a constant iterator, and the default Reference
+argument will be correct for all lvalue iterators.
+
+
As a matter of fact, node_iterator and const_node_iterator
+are so similar that it makes sense to factor the common code out
+into a template as follows:
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
+node_iterator where a node_const_iterator was expected,
+just as you can with std::list<int>'s iterator and
+const_iterator. Furthermore, given a node_iterator and a
+node_const_iterator into the same list, we should be able to
+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 34:
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.
+If we try to convert from node_const_iterator to
+node_iterator, we'll get an error when the converting
+constructor tries to initialize node_iterator's m_node, a
+node* with a nodeconst*. So what's the problem?
+
The problem is that
+boost::is_convertible<node_const_iterator,node_iterator>::value
+will be true, but it should be false. is_convertible
+lies because it can only see as far as the declaration of
+node_iter's converting constructor, but can't look inside at
+the definition to make sure it will compile. A perfect solution
+would make node_iter's converting constructor disappear when
+the m_node conversion would fail.
+
In fact, that sort of magic is possible using
+boost::enable_if. By rewriting the converting constructor as
+follows, we can remove it from the overload set when it's not
+appropriate:
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
+even be superior.
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
@@ -460,6 +1091,8 @@ object of type X, X, and z
is a constant object of a random access traversal iterator type
interoperable with X.
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
@@ -728,5 +1356,11 @@ return tmp -= n;
+
+
diff --git a/doc/iterator_facade_ref.rst b/doc/iterator_facade_ref.rst
index c763573..54efe9d 100644
--- a/doc/iterator_facade_ref.rst
+++ b/doc/iterator_facade_ref.rst
@@ -136,6 +136,11 @@ 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`:
+
+``iterator_facade`` Core Operations
+'''''''''''''''''''''''''''''''''''
+
+--------------------+----------------------+-------------------------------------+---------------------------+
|Expression |Return Type |Assertion/Note |Used to implement Iterator |
| | | |Concept(s) |
@@ -143,21 +148,18 @@ interoperable with ``X``.
|``c.dereference()`` |``F::reference`` | |Readable Iterator, Writable|
| | | |Iterator |
+--------------------+----------------------+-------------------------------------+---------------------------+
-|``c.equal(b)`` |convertible to bool |true iff ``b`` and ``c`` are |Single Pass Iterator |
-| | |equivalent. | |
-+--------------------+----------------------+-------------------------------------+---------------------------+
|``c.equal(y)`` |convertible to bool |true iff ``c`` and ``y`` refer to the|Single Pass Iterator |
| | |same position. Implements ``c == y``| |
| | |and ``c != y``. | |
+--------------------+----------------------+-------------------------------------+---------------------------+
-|``a.advance(n)`` |unused | |Random Access Traversal |
-| | | |Iterator |
-+--------------------+----------------------+-------------------------------------+---------------------------+
|``a.increment()`` |unused | |Incrementable Iterator |
+--------------------+----------------------+-------------------------------------+---------------------------+
|``a.decrement()`` |unused | |Bidirectional Traversal |
| | | |Iterator |
+--------------------+----------------------+-------------------------------------+---------------------------+
+|``a.advance(n)`` |unused | |Random Access Traversal |
+| | | |Iterator |
++--------------------+----------------------+-------------------------------------+---------------------------+
|``c.distance_to(b)``|convertible to |equivalent to ``distance(c, b)`` |Random Access Traversal |
| |``F::difference_type``| |Iterator |
+--------------------+----------------------+-------------------------------------+---------------------------+
diff --git a/doc/iterator_facade_tutorial.rst b/doc/iterator_facade_tutorial.rst
index 3437bef..553b7cb 100755
--- a/doc/iterator_facade_tutorial.rst
+++ b/doc/iterator_facade_tutorial.rst
@@ -12,7 +12,7 @@ example of a linked list of polymorphic objects.
The Problem
-----------
-Say we've written a polymorphic linked list node as follows::
+Say we've written a polymorphic linked list node base class::
# include
@@ -20,22 +20,24 @@ Say we've written a polymorphic linked list node as follows::
{
node_base() : m_next(0) {}
+ // Each node manages all of its tail nodes
virtual ~node_base() { delete m_next; }
+ // Access the rest of the list
node_base* next() const { return m_next; }
// print to the stream
virtual void print(std::ostream& s) const = 0;
// double the value
- virtual void twice() = 0;
+ virtual void double_me() = 0;
void append(node_base* p)
{
- if (m_next)
- m_next->append(p);
+ if (m_next)
+ m_next->append(p);
else
- m_next = p;
+ m_next = p;
}
private:
@@ -53,7 +55,7 @@ specializations of the following template::
{}
void print(std::ostream& s) const { s << this->m_value; }
- void twice() { m_value += m_value; }
+ void double_me() { m_value += m_value; }
private:
T m_value;
@@ -67,7 +69,422 @@ And we can print any node using the following streaming operator::
return s;
}
+Our first challenge is to build an appropriate iterator over these
+lists.
-.. sidebar:: Note
+A Basic Iterator Using ``iterator_facade``
+------------------------------------------
+
+Template Parameters
+...................
+
+The first step in building a concrete iterator with iterator_facade
+is to decide what its template parameters will be.
+
+``Derived``
+'''''''''''
+
+Because ``iterator_facade`` is meant to be used with the CRTP
+[Cop95]_ the first parameter is the iterator class name itself,
+``node_iterator``.
+
+``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``
+'''''''''''''''''''''''
+
+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
+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 [#category]_.
+
+.. [#category] ``iterator_facade`` also supports old-style category
+ tags, so we could've passed ``std::forward_iterator_tag`` here;
+ either way, the resulting iterator's ``iterator_category`` will
+ end up being ``std::forward_iterator_tag``.
+
+``Reference``
+'''''''''''''
+
+The ``Reference`` argument becomes the type returned by
+``node_iterator``\ 's dereference operation, and will also be the
+same as ``std::iterator_traits::reference``. The
+library's default for this parameter is ``Value&``; since
+``node_base&`` is a good choice for the iterator's ``reference``
+type, we can omit this argument, or pass ``use_default``.
+
+``Difference``
+''''''''''''''
+
+The ``Difference`` argument determines how the distance between
+two ``node_iterator``\ s will be measured and will also be the
+same as ``std::iterator_traits::difference_type``.
+The library's default for ``Difference`` is ``std::ptrdiff_t``, an
+appropriate type for measuring the distance between any two
+addresses in memory, and one that works for almost any iterator,
+so we can omit this argument, too.
+
+The declaration of ``node_iterator`` will therefore look something
+like::
+
+ # include "node.hpp"
+ # include
+
+ class node_iterator
+ : public boost::iterator_facade<
+ node_iterator
+ , node_base
+ , boost::forward_traversal_tag
+ >
+ {
+ ...
+ };
+
+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 [#default]_.
+Our ``node_iterator`` then becomes::
+
+ # include "node.hpp"
+ # include
+
+ class node_iterator
+ : public boost::iterator_facade<
+ node_iterator
+ , node_base
+ , boost::forward_traversal_tag
+ >
+ {
+ public:
+ node_iterator()
+ : m_node(0)
+ {}
+
+ explicit node_iterator(node_base* p)
+ : m_node(p)
+ {}
+
+ private:
+ ...
+ node_base* m_node;
+ };
+
+.. [#default] 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.
+
+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
+because ``node_iterator`` needs to satisfy the requirements for
+`readable iterator`_, `single pass iterator`_, and `incrementable
+iterator`_.
+
+__ `core operations`_
+
+We therefore need to supply ``dereference``,
+``equal``, and ``increment`` members. We don't want these members
+to become part of ``node_iterator``\ 's public interface, so we can
+make them private and grant friendship to
+``boost::iterator_core_access``, a "back-door" that
+``iterator_facade`` uses to get access to the core operations::
+
+ # include "node.hpp"
+ # include
+
+ class node_iterator
+ : public boost::iterator_facade<
+ node_iterator
+ , node_base
+ , boost::forward_traversal_tag
+ >
+ {
+ public:
+ node_iterator()
+ : m_node(0) {}
+
+ explicit node_iterator(node_base* p)
+ : m_node(p) {}
+
+ private:
+ friend class boost::iterator_core_access;
+
+ void increment() { m_node = m_node->next(); }
+
+ bool equal(node_iterator const& other) const
+ {
+ return this->m_node == other.m_node;
+ }
+
+ node_base& dereference() const { return *m_node; }
+
+ node_base* m_node;
+ };
+
+Voilą; a complete and conforming readable, forward-traversal
+iterator! For a working example of its use, see `this program`__.
+
+__ ../example/node_iterator1.cpp
+
+A constant ``node_iterator``
+----------------------------
+
+.. Sidebar:: Constant and Mutable iterators
+
+ The term **mutable iterator** means an iterator through which
+ the object it references (its "referent") can be modified. A
+ **constant iterator** is one which doesn't allow modification of
+ its referent.
+
+ The words *constant* and *mutable* don't refer to the ability to
+ modify the iterator itself. For example, an ``int const*`` is a
+ non-\ ``const`` *constant iterator*, which can be incremented
+ but doesn't allow modification of its referent, and ``int*
+ const`` is a ``const`` *mutable iterator*, which cannot be
+ modified but which allows modification of its referent.
+
+ Confusing? We agree, but those are the standard terms. It
+ probably doesn't help much that a container's constant iterator
+ is called ``const_iterator``.
+
+Now, our ``node_iterator`` gives clients access to both ``node``\
+'s ``print(std::ostream&) const`` member function, but also its
+mutating ``double_me()`` member. If we wanted to build a
+*constant* ``node_iterator``, we'd only have to make three
+changes:
+
+.. parsed-literal::
+
+ class const_node_iterator
+ : public boost::iterator_facade<
+ node_iterator
+ , node_base **const**
+ , boost::forward_traversal_tag
+ >
+ {
+ public:
+ const_node_iterator()
+ : m_node(0) {}
+
+ explicit const_node_iterator(node_base* p)
+ : m_node(p) {}
+
+ private:
+ friend class boost::iterator_core_access;
+
+ void increment() { m_node = m_node->next(); }
+
+ bool equal(const_node_iterator const& other) const
+ {
+ return this->m_node == other.m_node;
+ }
+
+ node_base **const**\ & dereference() const { return \*m_node; }
+
+ node_base **const**\ * m_node;
+ };
+
+.. Sidebar:: ``const`` and an iterator's ``value_type``
+
+ The C++ standard requires an iterator's ``value_type`` *not* be
+ ``const``\ -qualified, so ``iterator_facade`` strips the
+ ``const`` from its ``Value`` parameter in order to produce the
+ iterator's ``value_type``. Making the ``Value`` argument
+ ``const`` provides a useful hint to ``iterator_facade`` that the
+ iterator is a *constant iterator*, and the default ``Reference``
+ argument will be correct for all lvalue iterators.
+
+As a matter of fact, ``node_iterator`` and ``const_node_iterator``
+are so similar that it makes sense to factor the common code out
+into a template as follows::
+
+ template
+ class node_iter
+ : public boost::iterator_facade<
+ node_iter
+ , Value
+ , boost::forward_traversal_tag
+ >
+ {
+ public:
+ node_iter()
+ : m_node(0) {}
+
+ explicit node_iter(Value* p)
+ : m_node(p) {}
+
+ private:
+ friend class boost::iterator_core_access;
+
+ bool equal(node_iter const& other) const
+ {
+ return this->m_node == other.m_node;
+ }
+
+ void increment()
+ { m_node = m_node->next(); }
+
+ Value& dereference() const
+ { return *m_node; }
+
+ Value* m_node;
+ };
+ typedef node_iter node_iterator;
+ typedef node_iter node_const_iterator;
+
+
+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
+``node_iterator`` where a ``node_const_iterator`` was expected,
+just as you can with ``std::list``\ 's ``iterator`` and
+``const_iterator``. Furthermore, given a ``node_iterator`` and a
+``node_const_iterator`` into the same list, we should be able to
+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 [#broken]_ [#random]_::
+
+ template
+ class node_iter
+ : public boost::iterator_facade<
+ node_iter
+ , Value
+ , boost::forward_traversal_tag
+ >
+ {
+ public:
+ node_iter()
+ : m_node(0) {}
+
+ explicit node_iter(Value* p)
+ : m_node(p) {}
+
+ template
+ node_iter(node_iter const& other)
+ : m_node(other.m_node) {}
+
+ private:
+ friend class boost::iterator_core_access;
+ template friend class node_iter;
+
+ template
+ bool equal(node_iter const& other) const
+ {
+ return this->m_node == other.m_node;
+ }
+
+ void increment()
+ { m_node = m_node->next(); }
+
+ Value& dereference() const
+ { return *m_node; }
+
+ Value* m_node;
+ };
+ typedef impl::node_iterator node_iterator;
+ typedef impl::node_iterator node_const_iterator;
+
+.. [#broken] If you're using an older compiler and it can't handle
+ this example, see the `example code`__ for workarounds.
+
+.. [#random] If ``node_iterator`` had been a `random access
+ traversal iterator`_, we'd have had to templatize its
+ ``distance_to`` function as well.
+
+
+__ ../example/node_iterator2.hpp
+
+You can see an example program which exercises our interoperable
+iterators `here`__.
+
+__ ../example/node_iterator2.cpp
+
+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``.
+If we try to convert from ``node_const_iterator`` to
+``node_iterator``, we'll get an error when the converting
+constructor tries to initialize ``node_iterator``\ 's ``m_node``, a
+``node*`` with a ``node const*``. So what's the problem?
+
+The problem is that
+``boost::``\ |is_convertible|_\ ``::value``
+will be ``true``, but it should be ``false``. |is_convertible|_
+lies because it can only see as far as the *declaration* of
+``node_iter``\ 's converting constructor, but can't look inside at
+the *definition* to make sure it will compile. A perfect solution
+would make ``node_iter``\ 's converting constructor disappear when
+the ``m_node`` conversion would fail.
+
+.. |is_convertible| replace:: ``is_convertible``
+.. _is_convertible: ../../type_traits/index.html#relationships
+
+In fact, that sort of magic is possible using
+|enable_if|__. By rewriting the converting constructor as
+follows, we can remove it from the overload set when it's not
+appropriate::
+
+ template
+ node_iter(
+ node_iter const& other
+ , typename boost::enable_if<
+ boost::is_convertible
+ , enabler
+ >::type = enabler()
+ )
+ : m_node(other.m_node) {}
+
+.. |enable_if| replace:: ``boost::enable_if``
+__ ../../utility/enable_if.html
+
+
+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
+even be superior.
+
+.. |iterator_adaptor| replace:: ``iterator_adaptor``
+__ iterator_adaptor.html
+
+.. _`iterator traversal concept`: new-iter-concepts.html#iterator-traversal-concepts-lib-iterator-traversal
+.. _`readable iterator`: new-iter-concepts.html#readable-iterators-lib-readable-iterators
+.. _`lvalue iterator`: new-iter-concepts.html#lvalue-iterators-lib-lvalue-iterators
+.. _`single pass iterator`: new-iter-concepts.html#single-pass-iterators-lib-single-pass-iterators
+.. _`incrementable iterator`: new-iter-concepts.html#incrementable-iterators-lib-incrementable-iterators
+.. _`forward traversal iterator`: new-iter-concepts.html#forward-traversal-iterators-lib-forward-traversal-iterators
+.. _`bidirectional traversal iterator`: new-iter-concepts.html#bidirectional-traversal-iterators-lib-bidirectional-traversal-iterators
+.. _`random access traversal iterator`: new-iter-concepts.html#random-access-traversal-iterators-lib-random-access-traversal-iterators
- This is in progress; check the ../example directory for code.
\ No newline at end of file
diff --git a/doc/new-iter-concepts.html b/doc/new-iter-concepts.html
index 8b40d3e..ec815a3 100755
--- a/doc/new-iter-concepts.html
+++ b/doc/new-iter-concepts.html
@@ -3,13 +3,240 @@
-
+
New Iterator Concepts
-
+
@@ -881,5 +1108,11 @@ LocalWords: incrementable xxx min prev inplace png oldeqnew AccessTag struct
LocalWords: TraversalTag typename lvalues DWA Hmm JGS mis enum -->