• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1[section:adaptor Iterator Adaptor]
2
3The `iterator_adaptor` class template adapts some `Base` [#base]_
4type to create a new iterator.  Instantiations of `iterator_adaptor`
5are derived from a corresponding instantiation of `iterator_facade`
6and implement the core behaviors in terms of the `Base` type. In
7essence, `iterator_adaptor` merely forwards all operations to an
8instance of the `Base` type, which it stores as a member.
9
10.. [#base] The term "Base" here does not refer to a base class and is
11   not meant to imply the use of derivation. We have followed the lead
12   of the standard library, which provides a base() function to access
13   the underlying iterator object of a `reverse_iterator` adaptor.
14
15The user of `iterator_adaptor` creates a class derived from an
16instantiation of `iterator_adaptor` and then selectively
17redefines some of the core member functions described in the
18`iterator_facade` core requirements table. The `Base` type need
19not meet the full requirements for an iterator; it need only
20support the operations used by the core interface functions of
21`iterator_adaptor` that have not been redefined in the user's
22derived class.
23
24Several of the template parameters of `iterator_adaptor` default
25to `use_default`. This allows the
26user to make use of a default parameter even when she wants to
27specify a parameter later in the parameter list.  Also, the
28defaults for the corresponding associated types are somewhat
29complicated, so metaprogramming is required to compute them, and
30`use_default` can help to simplify the implementation.  Finally,
31the identity of the `use_default` type is not left unspecified
32because specification helps to highlight that the `Reference`
33template parameter may not always be identical to the iterator's
34`reference` type, and will keep users from making mistakes based on
35that assumption.
36
37[section:adaptor_reference Reference]
38
39[h2 Synopsis]
40
41  template <
42      class Derived
43    , class Base
44    , class Value               = use_default
45    , class CategoryOrTraversal = use_default
46    , class Reference           = use_default
47    , class Difference = use_default
48  >
49  class iterator_adaptor
50    : public iterator_facade<Derived, *V'*, *C'*, *R'*, *D'*> // see details
51  {
52      friend class iterator_core_access;
53   public:
54      iterator_adaptor();
55      explicit iterator_adaptor(Base const& iter);
56      typedef Base base_type;
57      Base const& base() const;
58   protected:
59      typedef iterator_adaptor iterator_adaptor\_;
60      Base const& base_reference() const;
61      Base& base_reference();
62   private: // Core iterator interface for iterator_facade.
63      typename iterator_adaptor::reference dereference() const;
64
65      template <
66          class OtherDerived, class OtherIterator, class V, class C, class R, class D
67      >
68      bool equal(iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D> const& x) const;
69
70      void advance(typename iterator_adaptor::difference_type n);
71      void increment();
72      void decrement();
73
74      template <
75          class OtherDerived, class OtherIterator, class V, class C, class R, class D
76      >
77      typename iterator_adaptor::difference_type distance_to(
78          iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D> const& y) const;
79
80   private:
81      Base m_iterator; // exposition only
82  };
83
84__ base_parameters_
85
86.. _requirements:
87
88[h2 Requirements]
89
90`static_cast<Derived*>(iterator_adaptor*)` shall be well-formed.
91The `Base` argument shall be Assignable and Copy Constructible.
92
93
94.. _base_parameters:
95
96[h2 Base Class Parameters]
97
98The *V'*, *C'*, *R'*, and *D'* parameters of the `iterator_facade`
99used as a base class in the summary of `iterator_adaptor`
100above are defined as follows:
101
102[pre
103   *V'* = if (Value is use_default)
104             return iterator_traits<Base>::value_type
105         else
106             return Value
107
108   *C'* = if (CategoryOrTraversal is use_default)
109             return iterator_traversal<Base>::type
110         else
111             return CategoryOrTraversal
112
113   *R'* = if (Reference is use_default)
114             if (Value is use_default)
115                 return iterator_traits<Base>::reference
116             else
117                 return Value&
118         else
119             return Reference
120
121   *D'* = if (Difference is use_default)
122             return iterator_traits<Base>::difference_type
123         else
124             return Difference
125]
126
127[h2 Operations]
128
129[h3 Public]
130
131
132  iterator_adaptor();
133
134[*Requires:] The `Base` type must be Default Constructible.[br]
135[*Returns:] An instance of `iterator_adaptor` with
136    `m_iterator` default constructed.
137
138
139  explicit iterator_adaptor(Base const& iter);
140
141[*Returns:] An instance of `iterator_adaptor` with
142    `m_iterator` copy constructed from `iter`.
143
144  Base const& base() const;
145
146[*Returns:] `m_iterator`
147
148
149[h3 Protected]
150
151  Base const& base_reference() const;
152
153[*Returns:] A const reference to `m_iterator`.
154
155
156  Base& base_reference();
157
158[*Returns:] A non-const reference to `m_iterator`.
159
160[h3 Private]
161
162  typename iterator_adaptor::reference dereference() const;
163
164[*Returns:] `*m_iterator`
165
166
167  template <
168  class OtherDerived, class OtherIterator, class V, class C, class R, class D
169  >
170  bool equal(iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D> const& x) const;
171
172[*Returns:] `m_iterator == x.base()`
173
174
175  void advance(typename iterator_adaptor::difference_type n);
176
177[*Effects:] `m_iterator += n;`
178
179  void increment();
180
181[*Effects:] `++m_iterator;`
182
183  void decrement();
184
185[*Effects:] `--m_iterator;`
186
187
188  template <
189      class OtherDerived, class OtherIterator, class V, class C, class R, class D
190  >
191  typename iterator_adaptor::difference_type distance_to(
192      iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D> const& y) const;
193
194[*Returns:] `y.base() - m_iterator`
195
196[endsect]
197
198[section:adaptor_tutorial Tutorial]
199
200In this section we'll further refine the `node_iter` class
201template we developed in the |fac_tut|_.  If you haven't already
202read that material, you should go back now and check it out because
203we're going to pick up right where it left off.
204
205.. |fac_tut| replace:: `iterator_facade` tutorial
206.. _fac_tut: iterator_facade.html#tutorial-example
207
208[blurb [*`node_base*` really *is* an iterator][br][br]
209  It's not really a very interesting iterator, since `node_base`
210  is an abstract class: a pointer to a `node_base` just points
211  at some base subobject of an instance of some other class, and
212  incrementing a `node_base*` moves it past this base subobject
213  to who-knows-where?  The most we can do with that incremented
214  position is to compare another `node_base*` to it.  In other
215  words, the original iterator traverses a one-element array.
216]
217
218You probably didn't think of it this way, but the `node_base*`
219object that underlies `node_iterator` is itself an iterator,
220just like all other pointers.  If we examine that pointer closely
221from an iterator perspective, we can see that it has much in common
222with the `node_iterator` we're building.  First, they share most
223of the same associated types (`value_type`, `reference`,
224`pointer`, and `difference_type`).  Second, even some of the
225core functionality is the same: `operator*` and `operator==` on
226the `node_iterator` return the result of invoking the same
227operations on the underlying pointer, via the `node_iterator`\ 's
228|dereference_and_equal|_).  The only real behavioral difference
229between `node_base*` and `node_iterator` can be observed when
230they are incremented: `node_iterator` follows the
231`m_next` pointer, while `node_base*` just applies an address offset.
232
233.. |dereference_and_equal| replace:: `dereference` and `equal` member functions
234.. _dereference_and_equal: iterator_facade.html#implementing-the-core-operations
235
236It turns out that the pattern of building an iterator on another
237iterator-like type (the `Base` [#base]_ type) while modifying
238just a few aspects of the underlying type's behavior is an
239extremely common one, and it's the pattern addressed by
240`iterator_adaptor`.  Using `iterator_adaptor` is very much like
241using `iterator_facade`, but because iterator_adaptor tries to
242mimic as much of the `Base` type's behavior as possible, we
243neither have to supply a `Value` argument, nor implement any core
244behaviors other than `increment`.  The implementation of
245`node_iter` is thus reduced to:
246
247  template <class Value>
248  class node_iter
249    : public boost::iterator_adaptor<
250          node_iter<Value>                // Derived
251        , Value*                          // Base
252        , boost::use_default              // Value
253        , boost::forward_traversal_tag    // CategoryOrTraversal
254      >
255  {
256   private:
257      struct enabler {};  // a private type avoids misuse
258
259   public:
260      node_iter()
261        : node_iter::iterator_adaptor_(0) {}
262
263      explicit node_iter(Value* p)
264        : node_iter::iterator_adaptor_(p) {}
265
266      template <class OtherValue>
267      node_iter(
268          node_iter<OtherValue> const& other
269        , typename boost::enable_if<
270              boost::is_convertible<OtherValue*,Value*>
271            , enabler
272          >::type = enabler()
273      )
274        : node_iter::iterator_adaptor_(other.base()) {}
275
276   private:
277      friend class boost::iterator_core_access;
278      void increment() { this->base_reference() = this->base()->next(); }
279  };
280
281Note the use of `node_iter::iterator_adaptor_` here: because
282`iterator_adaptor` defines a nested `iterator_adaptor_` type
283that refers to itself, that gives us a convenient way to refer to
284the complicated base class type of `node_iter<Value>`. [Note:
285this technique is known not to work with Borland C++ 5.6.4 and
286Metrowerks CodeWarrior versions prior to 9.0]
287
288You can see an example program that exercises this version of the
289node iterators
290[example_link node_iterator3.cpp..here].
291
292
293In the case of `node_iter`, it's not very compelling to pass
294`boost::use_default` as `iterator_adaptor` 's `Value`
295argument; we could have just passed `node_iter` 's `Value`
296along to `iterator_adaptor`, and that'd even be shorter!  Most
297iterator class templates built with `iterator_adaptor` are
298parameterized on another iterator type, rather than on its
299`value_type`.  For example, `boost::reverse_iterator` takes an
300iterator type argument and reverses its direction of traversal,
301since the original iterator and the reversed one have all the same
302associated types, `iterator_adaptor` 's delegation of default
303types to its `Base` saves the implementor of
304`boost::reverse_iterator` from writing:
305
306   std::iterator_traits<Iterator>::*some-associated-type*
307
308at least four times.
309
310We urge you to review the documentation and implementations of
311|reverse_iterator|_ and the other Boost `specialized iterator
312adaptors`__ to get an idea of the sorts of things you can do with
313`iterator_adaptor`.  In particular, have a look at
314|transform_iterator|_, which is perhaps the most straightforward
315adaptor, and also |counting_iterator|_, which demonstrates that
316`iterator_adaptor`\ 's `Base` type needn't be an iterator.
317
318.. |reverse_iterator| replace:: `reverse_iterator`
319.. _reverse_iterator: reverse_iterator.html
320
321.. |counting_iterator| replace:: `counting_iterator`
322.. _counting_iterator: counting_iterator.html
323
324.. |transform_iterator| replace:: `transform_iterator`
325.. _transform_iterator: transform_iterator.html
326
327__ index.html#specialized-adaptors
328
329
330[endsect]
331
332[endsect]
333