• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
5In this section we'll walk through the implementation of a few
6iterators using ``iterator_facade``, based around the simple
7example of a linked list of polymorphic objects.  This example was
8inspired by a `posting`__ by Keith Macdonald on the `Boost-Users`_
9mailing list.
10
11.. _`Boost-Users`: http://www.boost.org/more/mailing_lists.htm#users
12
13__ http://thread.gmane.org/gmane.comp.lib.boost.user/5100
14
15The Problem
16-----------
17
18Say we've written a polymorphic linked list node base class::
19
20  # include <iostream>
21
22  struct node_base
23  {
24      node_base() : m_next(0) {}
25
26      // Each node manages all of its tail nodes
27      virtual ~node_base() { delete m_next; }
28
29      // Access the rest of the list
30      node_base* next() const { return m_next; }
31
32      // print to the stream
33      virtual void print(std::ostream& s) const = 0;
34
35      // double the value
36      virtual void double_me() = 0;
37
38      void append(node_base* p)
39      {
40          if (m_next)
41              m_next->append(p);
42          else
43              m_next = p;
44      }
45
46   private:
47      node_base* m_next;
48  };
49
50Lists can hold objects of different types by linking together
51specializations of the following template::
52
53  template <class T>
54  struct node : node_base
55  {
56      node(T x)
57        : m_value(x)
58      {}
59
60      void print(std::ostream& s) const { s << this->m_value; }
61      void double_me() { m_value += m_value; }
62
63   private:
64      T m_value;
65  };
66
67And we can print any node using the following streaming operator::
68
69  inline std::ostream& operator<<(std::ostream& s, node_base const& n)
70  {
71      n.print(s);
72      return s;
73  }
74
75Our first challenge is to build an appropriate iterator over these
76lists.
77
78A Basic Iterator Using ``iterator_facade``
79------------------------------------------
80
81We will construct a ``node_iterator`` class using inheritance from
82``iterator_facade`` to implement most of the iterator's operations.
83
84::
85
86  # include "node.hpp"
87  # include <boost/iterator/iterator_facade.hpp>
88
89  class node_iterator
90    : public boost::iterator_facade<...>
91  {
92     ...
93  };
94
95
96
97Template Arguments for ``iterator_facade``
98..........................................
99
100``iterator_facade`` has several template parameters, so we must decide
101what types to use for the arguments. The parameters are ``Derived``,
102``Value``, ``CategoryOrTraversal``, ``Reference``, and ``Difference``.
103
104
105``Derived``
106'''''''''''
107
108Because ``iterator_facade`` is meant to be used with the CRTP
109[Cop95]_ the first parameter is the iterator class name itself,
110``node_iterator``.
111
112``Value``
113'''''''''
114
115The ``Value`` parameter determines the ``node_iterator``\ 's
116``value_type``.  In this case, we are iterating over ``node_base``
117objects, so ``Value`` will be ``node_base``.
118
119
120``CategoryOrTraversal``
121'''''''''''''''''''''''
122
123Now we have to determine which `iterator traversal concept`_ our
124``node_iterator`` is going to model.  Singly-linked lists only have
125forward links, so our iterator can't can't be a `bidirectional
126traversal iterator`_.  Our iterator should be able to make multiple
127passes over the same linked list (unlike, say, an
128``istream_iterator`` which consumes the stream it traverses), so it
129must be a `forward traversal iterator`_.  Therefore, we'll pass
130``boost::forward_traversal_tag`` in this position [#category]_.
131
132.. [#category] ``iterator_facade`` also supports old-style category
133   tags, so we could have passed ``std::forward_iterator_tag`` here;
134   either way, the resulting iterator's ``iterator_category`` will
135   end up being ``std::forward_iterator_tag``.
136
137``Reference``
138'''''''''''''
139
140The ``Reference`` argument becomes the type returned by
141``node_iterator``\ 's dereference operation, and will also be the
142same as ``std::iterator_traits<node_iterator>::reference``.  The
143library's default for this parameter is ``Value&``; since
144``node_base&`` is a good choice for the iterator's ``reference``
145type, we can omit this argument, or pass ``use_default``.
146
147``Difference``
148''''''''''''''
149
150The ``Difference`` argument determines how the distance between
151two ``node_iterator``\ s will be measured and will also be the
152same as ``std::iterator_traits<node_iterator>::difference_type``.
153The library's default for ``Difference`` is ``std::ptrdiff_t``, an
154appropriate type for measuring the distance between any two
155addresses in memory, and one that works for almost any iterator,
156so we can omit this argument, too.
157
158The declaration of ``node_iterator`` will therefore look something
159like::
160
161  # include "node.hpp"
162  # include <boost/iterator/iterator_facade.hpp>
163
164  class node_iterator
165    : public boost::iterator_facade<
166          node_iterator
167        , node_base
168        , boost::forward_traversal_tag
169      >
170  {
171     ...
172  };
173
174Constructors and Data Members
175.............................
176
177Next we need to decide how to represent the iterator's position.
178This representation will take the form of data members, so we'll
179also need to write constructors to initialize them.  The
180``node_iterator``\ 's position is quite naturally represented using
181a pointer to a ``node_base``.  We'll need a constructor to build an
182iterator from a ``node_base*``, and a default constructor to
183satisfy the `forward traversal iterator`_ requirements [#default]_.
184Our ``node_iterator`` then becomes::
185
186  # include "node.hpp"
187  # include <boost/iterator/iterator_facade.hpp>
188
189  class node_iterator
190    : public boost::iterator_facade<
191          node_iterator
192        , node_base
193        , boost::forward_traversal_tag
194      >
195  {
196   public:
197      node_iterator()
198        : m_node(0)
199      {}
200
201      explicit node_iterator(node_base* p)
202        : m_node(p)
203      {}
204
205   private:
206      ...
207      node_base* m_node;
208  };
209
210.. [#default] Technically, the C++ standard places almost no
211   requirements on a default-constructed iterator, so if we were
212   really concerned with efficiency, we could've written the
213   default constructor to leave ``m_node`` uninitialized.
214
215Implementing the Core Operations
216................................
217
218The last step is to implement the `core operations`_ required by
219the concepts we want our iterator to model.  Referring to the
220table__, we can see that the first three rows are applicable
221because ``node_iterator`` needs to satisfy the requirements for
222`readable iterator`_, `single pass iterator`_, and `incrementable
223iterator`_.
224
225__ `core operations`_
226
227We therefore need to supply ``dereference``,
228``equal``, and ``increment`` members.  We don't want these members
229to become part of ``node_iterator``\ 's public interface, so we can
230make them private and grant friendship to
231``boost::iterator_core_access``, a "back-door" that
232``iterator_facade`` uses to get access to the core operations::
233
234  # include "node.hpp"
235  # include <boost/iterator/iterator_facade.hpp>
236
237  class node_iterator
238    : public boost::iterator_facade<
239          node_iterator
240        , node_base
241        , boost::forward_traversal_tag
242      >
243  {
244   public:
245      node_iterator()
246        : m_node(0) {}
247
248      explicit node_iterator(node_base* p)
249        : m_node(p) {}
250
251   private:
252      friend class boost::iterator_core_access;
253
254      void increment() { m_node = m_node->next(); }
255
256      bool equal(node_iterator const& other) const
257      {
258          return this->m_node == other.m_node;
259      }
260
261      node_base& dereference() const { return *m_node; }
262
263      node_base* m_node;
264  };
265
266Voil�; a complete and conforming readable, forward-traversal
267iterator!  For a working example of its use, see `this program`__.
268
269__ ../example/node_iterator1.cpp
270
271A constant ``node_iterator``
272----------------------------
273
274.. Sidebar:: Constant and Mutable iterators
275
276   The term **mutable iterator** means an iterator through which
277   the object it references (its "referent") can be modified.  A
278   **constant iterator** is one which doesn't allow modification of
279   its referent.
280
281   The words *constant* and *mutable* don't refer to the ability to
282   modify the iterator itself.  For example, an ``int const*`` is a
283   non-\ ``const`` *constant iterator*, which can be incremented
284   but doesn't allow modification of its referent, and ``int*
285   const`` is a ``const`` *mutable iterator*, which cannot be
286   modified but which allows modification of its referent.
287
288   Confusing?  We agree, but those are the standard terms.  It
289   probably doesn't help much that a container's constant iterator
290   is called ``const_iterator``.
291
292Now, our ``node_iterator`` gives clients access to both ``node``\
293's ``print(std::ostream&) const`` member function, but also its
294mutating ``double_me()`` member.  If we wanted to build a
295*constant* ``node_iterator``, we'd only have to make three
296changes:
297
298.. parsed-literal::
299
300  class const_node_iterator
301    : public boost::iterator_facade<
302          const_node_iterator
303        , node_base **const**
304        , boost::forward_traversal_tag
305      >
306  {
307   public:
308      const_node_iterator()
309        : m_node(0) {}
310
311      explicit const_node_iterator(node_base* p)
312        : m_node(p) {}
313
314   private:
315      friend class boost::iterator_core_access;
316
317      void increment() { m_node = m_node->next(); }
318
319      bool equal(const_node_iterator const& other) const
320      {
321          return this->m_node == other.m_node;
322      }
323
324      node_base **const**\ & dereference() const { return \*m_node; }
325
326      node_base **const**\ * m_node;
327  };
328
329.. Sidebar:: ``const`` and an iterator's ``value_type``
330
331   The C++ standard requires an iterator's ``value_type`` *not* be
332   ``const``\ -qualified, so ``iterator_facade`` strips the
333   ``const`` from its ``Value`` parameter in order to produce the
334   iterator's ``value_type``.  Making the ``Value`` argument
335   ``const`` provides a useful hint to ``iterator_facade`` that the
336   iterator is a *constant iterator*, and the default ``Reference``
337   argument will be correct for all lvalue iterators.
338
339As a matter of fact, ``node_iterator`` and ``const_node_iterator``
340are so similar that it makes sense to factor the common code out
341into a template as follows::
342
343  template <class Value>
344  class node_iter
345    : public boost::iterator_facade<
346          node_iter<Value>
347        , Value
348        , boost::forward_traversal_tag
349      >
350  {
351   public:
352      node_iter()
353        : m_node(0) {}
354
355      explicit node_iter(Value* p)
356        : m_node(p) {}
357
358   private:
359      friend class boost::iterator_core_access;
360
361      bool equal(node_iter<Value> const& other) const
362      {
363          return this->m_node == other.m_node;
364      }
365
366      void increment()
367      { m_node = m_node->next(); }
368
369      Value& dereference() const
370      { return *m_node; }
371
372      Value* m_node;
373  };
374  typedef node_iter<node_base> node_iterator;
375  typedef node_iter<node_base const> node_const_iterator;
376
377
378Interoperability
379----------------
380
381Our ``const_node_iterator`` works perfectly well on its own, but
382taken together with ``node_iterator`` it doesn't quite meet
383expectations.  For example, we'd like to be able to pass a
384``node_iterator`` where a ``node_const_iterator`` was expected,
385just as you can with ``std::list<int>``\ 's ``iterator`` and
386``const_iterator``.  Furthermore, given a ``node_iterator`` and a
387``node_const_iterator`` into the same list, we should be able to
388compare them for equality.
389
390This expected ability to use two different iterator types together
391is known as |interoperability|_.  Achieving interoperability in
392our case is as simple as templatizing the ``equal`` function and
393adding a templatized converting constructor [#broken]_ [#random]_::
394
395  template <class Value>
396  class node_iter
397    : public boost::iterator_facade<
398          node_iter<Value>
399        , Value
400        , boost::forward_traversal_tag
401      >
402  {
403   public:
404      node_iter()
405        : m_node(0) {}
406
407      explicit node_iter(Value* p)
408        : m_node(p) {}
409
410      template <class OtherValue>
411      node_iter(node_iter<OtherValue> const& other)
412        : m_node(other.m_node) {}
413
414   private:
415      friend class boost::iterator_core_access;
416      template <class> friend class node_iter;
417
418      template <class OtherValue>
419      bool equal(node_iter<OtherValue> const& other) const
420      {
421          return this->m_node == other.m_node;
422      }
423
424      void increment()
425      { m_node = m_node->next(); }
426
427      Value& dereference() const
428      { return *m_node; }
429
430      Value* m_node;
431  };
432  typedef impl::node_iterator<node_base> node_iterator;
433  typedef impl::node_iterator<node_base const> node_const_iterator;
434
435.. |interoperability| replace:: **interoperability**
436.. _interoperability: new-iter-concepts.html#interoperable-iterators-lib-interoperable-iterators
437
438.. [#broken] If you're using an older compiler and it can't handle
439   this example, see the `example code`__ for workarounds.
440
441.. [#random] If ``node_iterator`` had been a `random access
442   traversal iterator`_, we'd have had to templatize its
443   ``distance_to`` function as well.
444
445
446__ ../example/node_iterator2.hpp
447
448You can see an example program which exercises our interoperable
449iterators `here`__.
450
451__ ../example/node_iterator2.cpp
452
453Telling the Truth
454-----------------
455
456Now ``node_iterator`` and ``node_const_iterator`` behave exactly as
457you'd expect... almost.  We can compare them and we can convert in
458one direction: from ``node_iterator`` to ``node_const_iterator``.
459If we try to convert from ``node_const_iterator`` to
460``node_iterator``, we'll get an error when the converting
461constructor tries to initialize ``node_iterator``\ 's ``m_node``, a
462``node*`` with a ``node const*``.  So what's the problem?
463
464The problem is that
465``boost::``\ |is_convertible|_\ ``<node_const_iterator,node_iterator>::value``
466will be ``true``, but it should be ``false``.  |is_convertible|_
467lies because it can only see as far as the *declaration* of
468``node_iter``\ 's converting constructor, but can't look inside at
469the *definition* to make sure it will compile.  A perfect solution
470would make ``node_iter``\ 's converting constructor disappear when
471the ``m_node`` conversion would fail.
472
473.. |is_convertible| replace:: ``is_convertible``
474.. _is_convertible:  ../../type_traits/index.html#relationships
475
476In fact, that sort of magic is possible using
477|enable_if|__.  By rewriting the converting constructor as
478follows, we can remove it from the overload set when it's not
479appropriate::
480
481  #include <boost/type_traits/is_convertible.hpp>
482  #include <boost/utility/enable_if.hpp>
483
484    ...
485
486  private:
487    struct enabler {};
488
489  public:
490    template <class OtherValue>
491    node_iter(
492        node_iter<OtherValue> const& other
493      , typename boost::enable_if<
494            boost::is_convertible<OtherValue*,Value*>
495          , enabler
496        >::type = enabler()
497    )
498      : m_node(other.m_node) {}
499
500.. |enable_if| replace:: ``boost::enable_if``
501__ ../../utility/enable_if.html
502
503
504Wrap Up
505-------
506
507This concludes our ``iterator_facade`` tutorial, but before you
508stop reading we urge you to take a look at |iterator_adaptor|__.
509There's another way to approach writing these iterators which might
510even be superior.
511
512.. |iterator_adaptor| replace:: ``iterator_adaptor``
513__ iterator_adaptor.html
514
515.. _`iterator traversal concept`: new-iter-concepts.html#iterator-traversal-concepts-lib-iterator-traversal
516.. _`readable iterator`: new-iter-concepts.html#readable-iterators-lib-readable-iterators
517.. _`lvalue iterator`: new-iter-concepts.html#lvalue-iterators-lib-lvalue-iterators
518.. _`single pass iterator`: new-iter-concepts.html#single-pass-iterators-lib-single-pass-iterators
519.. _`incrementable iterator`: new-iter-concepts.html#incrementable-iterators-lib-incrementable-iterators
520.. _`forward traversal iterator`: new-iter-concepts.html#forward-traversal-iterators-lib-forward-traversal-iterators
521.. _`bidirectional traversal iterator`: new-iter-concepts.html#bidirectional-traversal-iterators-lib-bidirectional-traversal-iterators
522.. _`random access traversal iterator`: new-iter-concepts.html#random-access-traversal-iterators-lib-random-access-traversal-iterators
523
524