iterator_facade_tutorial.rst

来自「Boost provides free peer-reviewed portab」· RST 代码 · 共 266 行

RST
266
字号
.. Copyright David Abrahams 2004. Use, modification and distribution is.. 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)In this section we'll walk through the implementation of a fewiterators using ``iterator_facade``, based around the simpleexample of a linked list of polymorphic objects.  This example wasinspired by a `posting`__ by Keith Macdonald on the `Boost-Users`_mailing list... _`Boost-Users`: http://www.boost.org/more/mailing_lists.htm#users__ http://thread.gmane.org/gmane.comp.lib.boost.user/5100The 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 togetherspecializations 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 theselists.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 decidewhat 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 haveforward links, so our iterator can't can't be a `bidirectionaltraversal iterator`_.  Our iterator should be able to make multiplepasses over the same linked list (unlike, say, an``istream_iterator`` which consumes the stream it traverses), so itmust 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``.``Reference``'''''''''''''The ``Reference`` argument becomes the type returned by``node_iterator``\ 's dereference operation, and will also be thesame as ``std::iterator_traits<node_iterator>::reference``.  Thelibrary'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 betweentwo ``node_iterator``\ s will be measured and will also be thesame as ``std::iterator_traits<node_iterator>::difference_type``.The library's default for ``Difference`` is ``std::ptrdiff_t``, anappropriate type for measuring the distance between any twoaddresses 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 somethinglike::  # 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'llalso need to write constructors to initialize them.  The``node_iterator``\ 's position is quite naturally represented usinga pointer to a ``node_base``.  We'll need a constructor to build aniterator from a ``node_base*``, and a default constructor tosatisfy 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.Implementing the Core Operations................................The last step is to implement the `core operations`_ required bythe concepts we want our iterator to model.  Referring to thetable__, we can see that the first three rows are applicablebecause ``node_iterator`` needs to satisfy the requirements for`readable iterator`_, `single pass iterator`_, and `incrementableiterator`_.  __ `core operations`_We therefore need to supply ``dereference``,``equal``, and ``increment`` members.  We don't want these membersto become part of ``node_iterator``\ 's public interface, so we canmake 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

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?