From a7eaa017b10c4a6a2ffe11d665e779ba51f6eff8 Mon Sep 17 00:00:00 2001
From: Dave Abrahams
-
-
-
+
-
-
-
-
-+
@@ -594,6 +595,8 @@ class function_output_iterator; iterator_facade is a base class template that implements the interface of standard iterators in terms of a few core functions and associated types, to be supplied by a derived iterator class.
++Class template iterator_facade
-Class template indirect_iterator
+Class template indirect_iterator
template < class Iterator @@ -1319,7 +1326,7 @@ satisfies the requirements of the concepts modeled by the indirect iterator as specified in the models section.-indirect_iterator requirements
+indirect_iterator requirements
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 +1342,7 @@ is not use_default, as implied default for the value_type member.
-indirect_iterator models
+indirect_iterator models
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 +1356,7 @@ the Iterator argument.
indirect_iterator models Lvalue Iterator.-indirect_iterator operations
+indirect_iterator operations
In addition to the operations required by the concepts modeled by indirect_iterator, indirect_iterator provides the following operations.
@@ -1441,13 +1448,13 @@ indirect_iterator(-Reverse iterator
+Reverse iterator
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.
-Class template reverse_iterator
+Class template reverse_iterator
template <class Iterator> class reverse_iterator @@ -1471,19 +1478,19 @@ private:-reverse_iterator requirements
+reverse_iterator requirements
The base Iterator must be a model of Bidirectional Traversal Iterator and Readable Iterator.
-reverse_iterator models
+reverse_iterator models
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.
-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.
@@ -1573,14 +1580,14 @@ return *..tmp;-Transform iterator
+Transform iterator
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.
-Class template transform_iterator
+Class template transform_iterator
template <class UnaryFunction, @@ -1611,7 +1618,7 @@ private:-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 @@ -1620,7 +1627,7 @@ where the type of f(*i) must b
The type Iterator must at least 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.
@@ -1638,7 +1645,7 @@ concept that is modeled by Iterator The value_type is remove_cv<remove_reference<reference> >::type.-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.
@@ -1731,7 +1738,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 over. A predicate function object controls which elements are skipped. When the @@ -1743,7 +1750,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.
-Class template filter_iterator
+Class template filter_iterator
template <class Predicate, class Iterator> class filter_iterator @@ -1779,7 +1786,7 @@ corresponding to each standard concept modeled by
-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 @@ -1790,11 +1797,11 @@ 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 what concepts the Iterator argument models, as specified in the following tables.
-+
-
@@ -1813,7 +1820,7 @@ following tables. +
-
@@ -1835,7 +1842,7 @@ following tables. +
@@ -1859,7 +1866,7 @@ following tables. -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.
@@ -1969,11 +1976,11 @@ or m_pred(*m_iter) -Counting iterator
+Counting iterator
counting_iterator adapts an arithmetic type, such as int, by adding an operator* that returns the current value of the object.
-Class template counting_iterator
+Class template counting_iterator
template < class Incrementable @@ -2001,13 +2008,13 @@ the cases when the Incrementable
-counting_iterator requirements
+counting_iterator requirements
The Incrementable type must be Default Constructible, Copy Constructible, and Assignable. The default distance is an implementation defined signed integral type.
-counting_iterator models
+counting_iterator models
counting_iterator models Readable Lvalue Iterator.
Furthermore, if you wish to create a counting iterator that is a Forward Traversal Iterator, then the following expressions must be valid:
@@ -2032,7 +2039,7 @@ i < j-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.
@@ -2107,7 +2114,7 @@ constructed from x.-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 @@ -2116,7 +2123,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 { @@ -2143,7 +2150,7 @@ public:-function_output_iterator requirements
+function_output_iterator requirements
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. @@ -2151,7 +2158,7 @@ The resulting function_output_iterator
-function_output_iterator operations
+function_output_iterator operations
explicit function_output_iterator(const UnaryFunction& f = UnaryFunction());
@@ -2192,7 +2199,7 @@ a copy of the unary function f -function_output_iterator::output_proxy operations
+function_output_iterator::output_proxy operations
output_proxy(UnaryFunction& f);
@@ -2227,10 +2234,10 @@ LocalWords: OtherIncrementable Coplien --> -
+
diff --git a/doc/facade-and-adaptor.rst b/doc/facade-and-adaptor.rst index 7cdff26..17174a9 100644 --- a/doc/facade-and-adaptor.rst +++ b/doc/facade-and-adaptor.rst @@ -297,6 +297,9 @@ Iterator facade [lib.iterator.facade] .. include:: iterator_facade_abstract.rst +Class template ``iterator_facade`` +---------------------------------- + .. include:: iterator_facade_ref.rst Iterator adaptor [lib.iterator.adaptor] @@ -304,6 +307,9 @@ Iterator adaptor [lib.iterator.adaptor] .. include:: iterator_adaptor_abstract.rst +Class template ``iterator_adaptor`` +----------------------------------- + .. include:: iterator_adaptor_ref.rst diff --git a/doc/filter_iterator.html b/doc/filter_iterator.html index bd57fd4..79f2ac4 100644 --- a/doc/filter_iterator.html +++ b/doc/filter_iterator.html @@ -3,7 +3,7 @@ - +Filter Iterator @@ -112,7 +112,7 @@ Input Iterator.The concepts that filter_iterator models are dependent on what concepts the Iterator argument models, as specified in the following tables.
-+
-
@@ -131,7 +131,7 @@ following tables. +
-
@@ -153,7 +153,7 @@ following tables. +
@@ -378,10 +378,10 @@ int main() -
+
diff --git a/doc/iterator_adaptor.html b/doc/iterator_adaptor.html index 218c193..f03707a 100644 --- a/doc/iterator_adaptor.html +++ b/doc/iterator_adaptor.html @@ -3,7 +3,7 @@ - +Iterator Adaptor @@ -324,10 +324,10 @@ typename iterator_adaptor::difference_type distance_to( -
+
diff --git a/doc/iterator_facade.html b/doc/iterator_facade.html index 814ff83..d825dec 100644 --- a/doc/iterator_facade.html +++ b/doc/iterator_facade.html @@ -3,7 +3,7 @@ - +Iterator Facade @@ -45,51 +45,44 @@ and associated types, to be supplied by a derived iterator class.--
- Overview
-
- Motivation
+- A Facade for Iterator Implementation
- Usage
- Iterator Core Access
- operator[]
- operator->
+- Reference
-- Tutorial Example
-Overview
--+Motivation
++-A Facade for Iterator Implementation
- - ---Introduction
-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.
---The Problem
-Say we've written a polymorphic linked list node base class:
--# include <iostream> - -struct node_base -{ - 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 double_me() = 0; - - void append(node_base* p) - { - if (m_next) - m_next->append(p); - else - m_next = p; - } - - private: - node_base* m_next; -}; --Lists can hold objects of different types by linking together -specializations of the following template:
--template <class T> -struct node : node_base -{ - node(T x) - : m_value(x) - {} - - void print(std::ostream& s) const { s << this->m_value; } - void double_me() { m_value += m_value; } - - private: - T m_value; -}; --And we can print any node using the following streaming operator:
--inline std::ostream& operator<<(std::ostream& s, node_base const& n) -{ - n.print(s); - return s; -} --Our first challenge is to build an appropriate iterator over these -lists.
---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.
--# include "node.hpp" -# include <boost/iterator/iterator_facade.hpp> - -class node_iterator - : public boost::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
-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 1.
--
-- - - - [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
-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.
---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. -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 - > -{ - ... -}; ----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. -Our node_iterator then becomes:
--# include "node.hpp" -# include <boost/iterator/iterator_facade.hpp> - -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; -}; ---
-- - - - [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. --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.
-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 <boost/iterator/iterator_facade.hpp> - -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.
---A constant node_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:
--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; -}; -- -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 Value> -class node_iter - : public boost::iterator_facade< - node_iter<Value> - , 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<Value> 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_base> node_iterator; -typedef node_iter<node_base const> 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<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 3 4:
--template <class Value> -class node_iter - : public boost::iterator_facade< - node_iter<Value> - , Value - , boost::forward_traversal_tag - > -{ - public: - node_iter() - : m_node(0) {} - - explicit node_iter(Value* p) - : m_node(p) {} - - template <class OtherValue> - node_iter(node_iter<OtherValue> const& other) - : m_node(other.m_node) {} - - private: - friend class boost::iterator_core_access; - template <class> friend class node_iter; - - template <class OtherValue> - bool equal(node_iter<OtherValue> 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_base> node_iterator; -typedef impl::node_iterator<node_base const> node_const_iterator; ---
-- - - - [3] If you're using an older compiler and it can't handle -this example, see the example code for workarounds. -
-- - - - [4] If node_iterator had been a random access -traversal iterator, we'd have had to templatize its -distance_to function as well. You can see an example program which exercises our interoperable -iterators here.
---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<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:
--template <class OtherValue> -node_iter( - node_iter<OtherValue> const& other - , typename boost::enable_if< - boost::is_convertible<OtherValue*,Value*> - , enabler - >::type = enabler() -) - : m_node(other.m_node) {} ----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.
--+Reference
+Reference
+ + +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. This example was +inspired by a posting by Keith Macdonald on the Boost-Users +mailing list.
+++The Problem
+Say we've written a polymorphic linked list node base class:
++# include <iostream> + +struct node_base +{ + 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 double_me() = 0; + + void append(node_base* p) + { + if (m_next) + m_next->append(p); + else + m_next = p; + } + + private: + node_base* m_next; +}; ++Lists can hold objects of different types by linking together +specializations of the following template:
++template <class T> +struct node : node_base +{ + node(T x) + : m_value(x) + {} + + void print(std::ostream& s) const { s << this->m_value; } + void double_me() { m_value += m_value; } + + private: + T m_value; +}; ++And we can print any node using the following streaming operator:
++inline std::ostream& operator<<(std::ostream& s, node_base const& n) +{ + n.print(s); + return s; +} ++Our first challenge is to build an appropriate iterator over these +lists.
+++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.
++# include "node.hpp" +# include <boost/iterator/iterator_facade.hpp> + +class node_iterator + : public boost::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
+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 1.
++
++ + + + [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
+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.
+++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. +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 + > +{ + ... +}; ++++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. +Our node_iterator then becomes:
++# include "node.hpp" +# include <boost/iterator/iterator_facade.hpp> + +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; +}; +++
++ + + + [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. ++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.
+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 <boost/iterator/iterator_facade.hpp> + +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.
+++A constant node_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:
++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; +}; ++ +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 Value> +class node_iter + : public boost::iterator_facade< + node_iter<Value> + , 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<Value> 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_base> node_iterator; +typedef node_iter<node_base const> 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<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 3 4:
++template <class Value> +class node_iter + : public boost::iterator_facade< + node_iter<Value> + , Value + , boost::forward_traversal_tag + > +{ + public: + node_iter() + : m_node(0) {} + + explicit node_iter(Value* p) + : m_node(p) {} + + template <class OtherValue> + node_iter(node_iter<OtherValue> const& other) + : m_node(other.m_node) {} + + private: + friend class boost::iterator_core_access; + template <class> friend class node_iter; + + template <class OtherValue> + bool equal(node_iter<OtherValue> 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_base> node_iterator; +typedef impl::node_iterator<node_base const> node_const_iterator; +++
++ + + + [3] If you're using an older compiler and it can't handle +this example, see the example code for workarounds. +
++ + + + [4] If node_iterator had been a random access +traversal iterator, we'd have had to templatize its +distance_to function as well. You can see an example program which exercises our interoperable +iterators here.
+++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<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:
++template <class OtherValue> +node_iter( + node_iter<OtherValue> const& other + , typename boost::enable_if< + boost::is_convertible<OtherValue*,Value*> + , enabler + >::type = enabler() +) + : m_node(other.m_node) {} ++++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.
+
diff --git a/doc/iterator_facade.rst b/doc/iterator_facade.rst index 3caab6d..b7b0397 100644 --- a/doc/iterator_facade.rst +++ b/doc/iterator_facade.rst @@ -20,22 +20,21 @@ .. contents:: Table of Contents -Overview -======== - -Motivation ----------- +A Facade for Iterator Implementation +==================================== .. include:: iterator_facade_body.rst + +Reference +--------- + +.. include:: iterator_facade_ref.rst + +.. _counting: counting_iterator.html + Tutorial Example ================ .. include:: iterator_facade_tutorial.rst -Reference -========= - -.. include:: iterator_facade_ref.rst - -.. _counting: counting_iterator.html diff --git a/doc/iterator_facade_ref.rst b/doc/iterator_facade_ref.rst index fd6960a..f879971 100644 --- a/doc/iterator_facade_ref.rst +++ b/doc/iterator_facade_ref.rst @@ -120,8 +120,8 @@ were defined to be:: {}; -``iterator_facade`` usage -------------------------- +``iterator_facade`` Requirements +................................ The following table describes the typical valid expressions on ``iterator_facade``\ 's ``Derived`` parameter, depending on the @@ -138,40 +138,39 @@ interoperable with ``X``. .. _`core operations`: -``iterator_facade`` 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`` refer to the|Single Pass Iterator | -| | |same position. Implements ``c == y``| | -| | |and ``c != y``. | | -+--------------------+----------------------+-------------------------------------+---------------------------+ -|``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 | -+--------------------+----------------------+-------------------------------------+---------------------------+ -|``c.distance_to(z)``|convertible to |equivalent to ``distance(c, z)``. |Random Access Traversal | -| |``F::difference_type``|Implements ``c - z``, ``c < z``, ``c |Iterator | -| | |<= z``, ``c > z``, and ``c >= c``. | | -+--------------------+----------------------+-------------------------------------+---------------------------+ + +--------------------+----------------------+-------------------------------------+---------------------------+ + |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. Implements ``c == y``| | + | | |and ``c != y``. | | + +--------------------+----------------------+-------------------------------------+---------------------------+ + |``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 | + +--------------------+----------------------+-------------------------------------+---------------------------+ + |``c.distance_to(z)``|convertible to |equivalent to ``distance(c, z)``. |Random Access Traversal | + | |``F::difference_type``|Implements ``c - z``, ``c < z``, ``c |Iterator | + | | |<= z``, ``c > z``, and ``c >= c``. | | + +--------------------+----------------------+-------------------------------------+---------------------------+ .. _facade iterator category: ``iterator_facade`` iterator category -------------------------------------- +..................................... The ``iterator_category`` member of ``iterator_facade`` is a type which satisfies the following conditions: @@ -219,7 +218,7 @@ is a type which satisfies the following conditions: ``iterator_facade`` operations ------------------------------- +.............................. The operations in this section are described in terms of operations on the core interface of ``Derived`` which may be inaccessible diff --git a/doc/iterator_facade_tutorial.rst b/doc/iterator_facade_tutorial.rst index 869e5d5..837fcbc 100755 --- a/doc/iterator_facade_tutorial.rst +++ b/doc/iterator_facade_tutorial.rst @@ -2,12 +2,15 @@ .. subject to the Boost Software License, Version 1.0. (See accompanying .. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -Introduction ------------- - 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. +example of a linked list of polymorphic objects. This example was +inspired by a `posting`__ by Keith Macdonald on the `Boost-Users`_ +mailing list. + +.. _`Boost-Users`: ../../../more/mailing_lists.htm#users + +__ http://thread.gmane.org/gmane.comp.lib.boost.user/5100 The Problem ----------- diff --git a/doc/new-iter-concepts.html b/doc/new-iter-concepts.html index ec815a3..6f2f033 100755 --- a/doc/new-iter-concepts.html +++ b/doc/new-iter-concepts.html @@ -9,234 +9,7 @@ - + @@ -1111,7 +884,7 @@ LocalWords: TraversalTag typename lvalues DWA Hmm JGS mis enum -->
diff --git a/doc/rst2html b/doc/rst2html new file mode 100755 index 0000000..845c11f --- /dev/null +++ b/doc/rst2html @@ -0,0 +1,7 @@ +#!/bin/sh +PYTHONPATH="c:/src/docutils/docutils;c:/src/docutils/docutils/extras" +export PYTHONPATH +python c:/src/docutils/docutils/tools/html.py -gdts $1 `echo $1 | sed 's/\(.*\)\..*/\1.html/'` + + + diff --git a/doc/style.tex b/doc/style.tex index a4fe2f9..681d6b3 100755 --- a/doc/style.tex +++ b/doc/style.tex @@ -20,13 +20,13 @@ % pagestyle % \usepackage{fancyhdr} \pagestyle{headings} -\setlength{\paperwidth}{7.375in} -\setlength{\paperheight}{9.25in} +\setlength{\paperwidth}{8.5in} +\setlength{\paperheight}{11in} \setlength{\oddsidemargin}{0.375in} \setlength{\evensidemargin}{0.375in} -\setlength{\textwidth}{5in} -\setlength{\textheight}{7.125in} +\setlength{\textwidth}{6.125in} +\setlength{\textheight}{8.875in} \setlength{\topmargin}{-0.375in} \setlength{\headheight}{0.25in}