facade_tutorial.qbk 15 KB

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