iterator_facade_tutorial.rst 16 KB

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