mirror of
				https://github.com/saitohirga/WSJT-X.git
				synced 2025-10-29 12:00:24 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			508 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			508 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| 
 | |
| [section:facade_tutorial Tutorial]
 | |
| 
 | |
| 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 
 | |
| [@http://thread.gmane.org/gmane.comp.lib.boost.user/5100 `posting`]
 | |
| by Keith Macdonald on the 
 | |
| [@http://www.boost.org/more/mailing_lists.htm#users `Boost-Users`]
 | |
| mailing list.
 | |
| 
 | |
| 
 | |
| [h2 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.
 | |
| 
 | |
| [h2 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<...>
 | |
|   {
 | |
|      ...
 | |
|   };
 | |
| 
 | |
| 
 | |
| 
 | |
| [h2 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`.
 | |
| 
 | |
| 
 | |
| [h3 `Derived`]
 | |
| 
 | |
| Because `iterator_facade` is meant to be used with the CRTP
 | |
| [Cop95]_ the first parameter is the iterator class name itself,
 | |
| `node_iterator`.
 | |
| 
 | |
| [h3 `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`.
 | |
| 
 | |
| 
 | |
| [h3 `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 have passed `std::forward_iterator_tag` here;
 | |
|    either way, the resulting iterator's `iterator_category` will
 | |
|    end up being `std::forward_iterator_tag`.
 | |
| 
 | |
| [h3 `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`.
 | |
| 
 | |
| [h3 `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<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
 | |
|       >
 | |
|   {
 | |
|      ...
 | |
|   };
 | |
| 
 | |
| 
 | |
| [h2 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 <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;
 | |
|   };
 | |
| 
 | |
| .. [#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.
 | |
| 
 | |
| [h2 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
 | |
| 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 <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;
 | |
|   };
 | |
| 
 | |
| Voila; a complete and conforming readable, forward-traversal
 | |
| iterator!  For a working example of its use, see 
 | |
| [@../example/node_iterator1.cpp `this program`].
 | |
| 
 | |
| __ ../example/node_iterator1.cpp
 | |
| 
 | |
| [h2 A constant `node_iterator`]
 | |
| 
 | |
| [blurb *Constant and Mutable iterators*[br][br]
 | |
| 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.[br][br]  
 | |
| 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.[br][br]
 | |
| 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:
 | |
| 
 | |
|   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;
 | |
|   };
 | |
| 
 | |
| [blurb `const` and an iterator's `value_type`[br][br]
 | |
| 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 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;
 | |
| 
 | |
| 
 | |
| [h2 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 [#broken]_ [#random]_:
 | |
| 
 | |
|   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;
 | |
| 
 | |
| .. |interoperability| replace:: **interoperability**
 | |
| .. _interoperability: new-iter-concepts.html#interoperable-iterators-lib-interoperable-iterators
 | |
| 
 | |
| .. [#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 
 | |
| [@../example/node_iterator2.cpp `here`].
 | |
| 
 | |
| 
 | |
| [h2 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.
 | |
| 
 | |
| .. |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:
 | |
| 
 | |
|   #include <boost/type_traits/is_convertible.hpp>
 | |
|   #include <boost/utility/enable_if.hpp>
 | |
| 
 | |
|     ...
 | |
| 
 | |
|   private: 
 | |
|     struct enabler {};
 | |
| 
 | |
|   public:
 | |
|     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) {}
 | |
| 
 | |
| .. |enable_if| replace:: `boost::enable_if`
 | |
| __ ../../utility/enable_if.html
 | |
| 
 | |
| 
 | |
| [h2 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
 | |
| 
 | |
| [endsect]
 |