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