]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/iterator/doc/iterator_facade_tutorial.rst
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / iterator / doc / iterator_facade_tutorial.rst
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
5 In this section we'll walk through the implementation of a few
6 iterators using ``iterator_facade``, based around the simple
7 example of a linked list of polymorphic objects. This example was
8 inspired by a `posting`__ by Keith Macdonald on the `Boost-Users`_
9 mailing 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
15 The Problem
16 -----------
17
18 Say 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
50 Lists can hold objects of different types by linking together
51 specializations 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
67 And 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
75 Our first challenge is to build an appropriate iterator over these
76 lists.
77
78 A Basic Iterator Using ``iterator_facade``
79 ------------------------------------------
80
81 We 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
97 Template Arguments for ``iterator_facade``
98 ..........................................
99
100 ``iterator_facade`` has several template parameters, so we must decide
101 what types to use for the arguments. The parameters are ``Derived``,
102 ``Value``, ``CategoryOrTraversal``, ``Reference``, and ``Difference``.
103
104
105 ``Derived``
106 '''''''''''
107
108 Because ``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
115 The ``Value`` parameter determines the ``node_iterator``\ 's
116 ``value_type``. In this case, we are iterating over ``node_base``
117 objects, so ``Value`` will be ``node_base``.
118
119
120 ``CategoryOrTraversal``
121 '''''''''''''''''''''''
122
123 Now we have to determine which `iterator traversal concept`_ our
124 ``node_iterator`` is going to model. Singly-linked lists only have
125 forward links, so our iterator can't can't be a `bidirectional
126 traversal iterator`_. Our iterator should be able to make multiple
127 passes over the same linked list (unlike, say, an
128 ``istream_iterator`` which consumes the stream it traverses), so it
129 must 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
140 The ``Reference`` argument becomes the type returned by
141 ``node_iterator``\ 's dereference operation, and will also be the
142 same as ``std::iterator_traits<node_iterator>::reference``. The
143 library's default for this parameter is ``Value&``; since
144 ``node_base&`` is a good choice for the iterator's ``reference``
145 type, we can omit this argument, or pass ``use_default``.
146
147 ``Difference``
148 ''''''''''''''
149
150 The ``Difference`` argument determines how the distance between
151 two ``node_iterator``\ s will be measured and will also be the
152 same as ``std::iterator_traits<node_iterator>::difference_type``.
153 The library's default for ``Difference`` is ``std::ptrdiff_t``, an
154 appropriate type for measuring the distance between any two
155 addresses in memory, and one that works for almost any iterator,
156 so we can omit this argument, too.
157
158 The declaration of ``node_iterator`` will therefore look something
159 like::
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
174 Constructors and Data Members
175 .............................
176
177 Next we need to decide how to represent the iterator's position.
178 This representation will take the form of data members, so we'll
179 also need to write constructors to initialize them. The
180 ``node_iterator``\ 's position is quite naturally represented using
181 a pointer to a ``node_base``. We'll need a constructor to build an
182 iterator from a ``node_base*``, and a default constructor to
183 satisfy the `forward traversal iterator`_ requirements [#default]_.
184 Our ``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
215 Implementing the Core Operations
216 ................................
217
218 The last step is to implement the `core operations`_ required by
219 the concepts we want our iterator to model. Referring to the
220 table__, we can see that the first three rows are applicable
221 because ``node_iterator`` needs to satisfy the requirements for
222 `readable iterator`_, `single pass iterator`_, and `incrementable
223 iterator`_.
224
225 __ `core operations`_
226
227 We therefore need to supply ``dereference``,
228 ``equal``, and ``increment`` members. We don't want these members
229 to become part of ``node_iterator``\ 's public interface, so we can
230 make 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
266 Voilà; a complete and conforming readable, forward-traversal
267 iterator! For a working example of its use, see `this program`__.
268
269 __ ../example/node_iterator1.cpp
270
271 A 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
292 Now, our ``node_iterator`` gives clients access to both ``node``\
293 's ``print(std::ostream&) const`` member function, but also its
294 mutating ``double_me()`` member. If we wanted to build a
295 *constant* ``node_iterator``, we'd only have to make three
296 changes:
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
339 As a matter of fact, ``node_iterator`` and ``const_node_iterator``
340 are so similar that it makes sense to factor the common code out
341 into 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
378 Interoperability
379 ----------------
380
381 Our ``const_node_iterator`` works perfectly well on its own, but
382 taken together with ``node_iterator`` it doesn't quite meet
383 expectations. For example, we'd like to be able to pass a
384 ``node_iterator`` where a ``node_const_iterator`` was expected,
385 just 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
388 compare them for equality.
389
390 This expected ability to use two different iterator types together
391 is known as |interoperability|_. Achieving interoperability in
392 our case is as simple as templatizing the ``equal`` function and
393 adding 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
448 You can see an example program which exercises our interoperable
449 iterators `here`__.
450
451 __ ../example/node_iterator2.cpp
452
453 Telling the Truth
454 -----------------
455
456 Now ``node_iterator`` and ``node_const_iterator`` behave exactly as
457 you'd expect... almost. We can compare them and we can convert in
458 one direction: from ``node_iterator`` to ``node_const_iterator``.
459 If we try to convert from ``node_const_iterator`` to
460 ``node_iterator``, we'll get an error when the converting
461 constructor tries to initialize ``node_iterator``\ 's ``m_node``, a
462 ``node*`` with a ``node const*``. So what's the problem?
463
464 The problem is that
465 ``boost::``\ |is_convertible|_\ ``<node_const_iterator,node_iterator>::value``
466 will be ``true``, but it should be ``false``. |is_convertible|_
467 lies because it can only see as far as the *declaration* of
468 ``node_iter``\ 's converting constructor, but can't look inside at
469 the *definition* to make sure it will compile. A perfect solution
470 would make ``node_iter``\ 's converting constructor disappear when
471 the ``m_node`` conversion would fail.
472
473 .. |is_convertible| replace:: ``is_convertible``
474 .. _is_convertible: ../../type_traits/index.html#relationships
475
476 In fact, that sort of magic is possible using
477 |enable_if|__. By rewriting the converting constructor as
478 follows, we can remove it from the overload set when it's not
479 appropriate::
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
504 Wrap Up
505 -------
506
507 This concludes our ``iterator_facade`` tutorial, but before you
508 stop reading we urge you to take a look at |iterator_adaptor|__.
509 There's another way to approach writing these iterators which might
510 even 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