iterator_adaptor_tutorial.rst 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. .. Copyright David Abrahams 2004. Use, modification and distribution is
  2. .. subject to the Boost Software License, Version 1.0. (See accompanying
  3. .. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  4. In this section we'll further refine the ``node_iter`` class
  5. template we developed in the |fac_tut|_. If you haven't already
  6. read that material, you should go back now and check it out because
  7. we're going to pick up right where it left off.
  8. .. |fac_tut| replace:: ``iterator_facade`` tutorial
  9. .. _fac_tut: iterator_facade.html#tutorial-example
  10. .. sidebar:: ``node_base*`` really *is* an iterator
  11. It's not really a very interesting iterator, since ``node_base``
  12. is an abstract class: a pointer to a ``node_base`` just points
  13. at some base subobject of an instance of some other class, and
  14. incrementing a ``node_base*`` moves it past this base subobject
  15. to who-knows-where? The most we can do with that incremented
  16. position is to compare another ``node_base*`` to it. In other
  17. words, the original iterator traverses a one-element array.
  18. You probably didn't think of it this way, but the ``node_base*``
  19. object that underlies ``node_iterator`` is itself an iterator,
  20. just like all other pointers. If we examine that pointer closely
  21. from an iterator perspective, we can see that it has much in common
  22. with the ``node_iterator`` we're building. First, they share most
  23. of the same associated types (``value_type``, ``reference``,
  24. ``pointer``, and ``difference_type``). Second, even some of the
  25. core functionality is the same: ``operator*`` and ``operator==`` on
  26. the ``node_iterator`` return the result of invoking the same
  27. operations on the underlying pointer, via the ``node_iterator``\ 's
  28. |dereference_and_equal|_). The only real behavioral difference
  29. between ``node_base*`` and ``node_iterator`` can be observed when
  30. they are incremented: ``node_iterator`` follows the
  31. ``m_next`` pointer, while ``node_base*`` just applies an address offset.
  32. .. |dereference_and_equal| replace:: ``dereference`` and ``equal`` member functions
  33. .. _dereference_and_equal: iterator_facade.html#implementing-the-core-operations
  34. It turns out that the pattern of building an iterator on another
  35. iterator-like type (the ``Base`` [#base]_ type) while modifying
  36. just a few aspects of the underlying type's behavior is an
  37. extremely common one, and it's the pattern addressed by
  38. ``iterator_adaptor``. Using ``iterator_adaptor`` is very much like
  39. using ``iterator_facade``, but because iterator_adaptor tries to
  40. mimic as much of the ``Base`` type's behavior as possible, we
  41. neither have to supply a ``Value`` argument, nor implement any core
  42. behaviors other than ``increment``. The implementation of
  43. ``node_iter`` is thus reduced to::
  44. template <class Value>
  45. class node_iter
  46. : public boost::iterator_adaptor<
  47. node_iter<Value> // Derived
  48. , Value* // Base
  49. , boost::use_default // Value
  50. , boost::forward_traversal_tag // CategoryOrTraversal
  51. >
  52. {
  53. private:
  54. struct enabler {}; // a private type avoids misuse
  55. public:
  56. node_iter()
  57. : node_iter::iterator_adaptor_(0) {}
  58. explicit node_iter(Value* p)
  59. : node_iter::iterator_adaptor_(p) {}
  60. template <class OtherValue>
  61. node_iter(
  62. node_iter<OtherValue> const& other
  63. , typename boost::enable_if<
  64. boost::is_convertible<OtherValue*,Value*>
  65. , enabler
  66. >::type = enabler()
  67. )
  68. : node_iter::iterator_adaptor_(other.base()) {}
  69. private:
  70. friend class boost::iterator_core_access;
  71. void increment() { this->base_reference() = this->base()->next(); }
  72. };
  73. Note the use of ``node_iter::iterator_adaptor_`` here: because
  74. ``iterator_adaptor`` defines a nested ``iterator_adaptor_`` type
  75. that refers to itself, that gives us a convenient way to refer to
  76. the complicated base class type of ``node_iter<Value>``. [Note:
  77. this technique is known not to work with Borland C++ 5.6.4 and
  78. Metrowerks CodeWarrior versions prior to 9.0]
  79. You can see an example program that exercises this version of the
  80. node iterators `here`__.
  81. __ ../example/node_iterator3.cpp
  82. In the case of ``node_iter``, it's not very compelling to pass
  83. ``boost::use_default`` as ``iterator_adaptor``\ 's ``Value``
  84. argument; we could have just passed ``node_iter``\ 's ``Value``
  85. along to ``iterator_adaptor``, and that'd even be shorter! Most
  86. iterator class templates built with ``iterator_adaptor`` are
  87. parameterized on another iterator type, rather than on its
  88. ``value_type``. For example, ``boost::reverse_iterator`` takes an
  89. iterator type argument and reverses its direction of traversal,
  90. since the original iterator and the reversed one have all the same
  91. associated types, ``iterator_adaptor``\ 's delegation of default
  92. types to its ``Base`` saves the implementor of
  93. ``boost::reverse_iterator`` from writing:
  94. .. parsed-literal::
  95. std::iterator_traits<Iterator>::*some-associated-type*
  96. at least four times.
  97. We urge you to review the documentation and implementations of
  98. |reverse_iterator|_ and the other Boost `specialized iterator
  99. adaptors`__ to get an idea of the sorts of things you can do with
  100. ``iterator_adaptor``. In particular, have a look at
  101. |transform_iterator|_, which is perhaps the most straightforward
  102. adaptor, and also |counting_iterator|_, which demonstrates that
  103. ``iterator_adaptor``\ 's ``Base`` type needn't be an iterator.
  104. .. |reverse_iterator| replace:: ``reverse_iterator``
  105. .. _reverse_iterator: reverse_iterator.html
  106. .. |counting_iterator| replace:: ``counting_iterator``
  107. .. _counting_iterator: counting_iterator.html
  108. .. |transform_iterator| replace:: ``transform_iterator``
  109. .. _transform_iterator: transform_iterator.html
  110. __ index.html#specialized-adaptors