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