blob: 7ca38096e2f7d7d765a2448df47ad1b01050b0aa [file] [log] [blame]
Brian Silverman59623332018-08-04 23:36:56 -07001
2[section:facade Iterator Facade]
3
4While the iterator interface is rich, there is a core subset of the
5interface that is necessary for all the functionality. We have
6identified the following core behaviors for iterators:
7
8* dereferencing
9* incrementing
10* decrementing
11* equality comparison
12* random-access motion
13* distance measurement
14
15In addition to the behaviors listed above, the core interface elements
16include the associated types exposed through iterator traits:
17`value_type`, `reference`, `difference_type`, and
18`iterator_category`.
19
20Iterator facade uses the Curiously Recurring Template
21Pattern (CRTP) [Cop95]_ so that the user can specify the behavior
22of `iterator_facade` in a derived class. Former designs used
23policy objects to specify the behavior, but that approach was
24discarded for several reasons:
25
261. the creation and eventual copying of the policy object may create
27 overhead that can be avoided with the current approach.
28
292. The policy object approach does not allow for custom constructors
30 on the created iterator types, an essential feature if
31 `iterator_facade` should be used in other library
32 implementations.
33
343. Without the use of CRTP, the standard requirement that an
35 iterator's `operator++` returns the iterator type itself
36 would mean that all iterators built with the library would
37 have to be specializations of `iterator_facade<...>`, rather
38 than something more descriptive like
39 `indirect_iterator<T*>`. Cumbersome type generator
40 metafunctions would be needed to build new parameterized
41 iterators, and a separate `iterator_adaptor` layer would be
42 impossible.
43
44[h2 Usage]
45
46The user of `iterator_facade` derives his iterator class from a
47specialization of `iterator_facade` and passes the derived
48iterator class as `iterator_facade`\ 's first template parameter.
49The order of the other template parameters have been carefully
50chosen to take advantage of useful defaults. For example, when
51defining a constant lvalue iterator, the user can pass a
52const-qualified version of the iterator's `value_type` as
53`iterator_facade`\ 's `Value` parameter and omit the
54`Reference` parameter which follows.
55
56The derived iterator class must define member functions implementing
57the iterator's core behaviors. The following table describes
58expressions which are required to be valid depending on the category
59of the derived iterator type. These member functions are described
60briefly below and in more detail in the iterator facade
61requirements.
62
63[table Core Interface
64 [
65 [Expression]
66 [Effects]
67 ]
68 [
69 [`i.dereference()`]
70 [Access the value referred to]
71 ]
72 [
73 [`i.equal(j)`]
74 [Compare for equality with `j`]
75 ]
76 [
77 [`i.increment()`]
78 [Advance by one position]
79 ]
80 [
81 [`i.decrement()`]
82 [Retreat by one position]
83 ]
84 [
85 [`i.advance(n)`]
86 [Advance by `n` positions]
87 ]
88 [
89 [`i.distance_to(j)`]
90 [Measure the distance to `j`]
91 ]
92]
93
94[/ .. Should we add a comment that a zero overhead implementation of iterator_facade is possible with proper inlining?]
95
96In addition to implementing the core interface functions, an iterator
97derived from `iterator_facade` typically defines several
98constructors. To model any of the standard iterator concepts, the
99iterator must at least have a copy constructor. Also, if the iterator
100type `X` is meant to be automatically interoperate with another
101iterator type `Y` (as with constant and mutable iterators) then
102there must be an implicit conversion from `X` to `Y` or from `Y`
103to `X` (but not both), typically implemented as a conversion
104constructor. Finally, if the iterator is to model Forward Traversal
105Iterator or a more-refined iterator concept, a default constructor is
106required.
107
108[h2 Iterator Core Access]
109
110`iterator_facade` and the operator implementations need to be able
111to access the core member functions in the derived class. Making the
112core member functions public would expose an implementation detail to
113the user. The design used here ensures that implementation details do
114not appear in the public interface of the derived iterator type.
115
116Preventing direct access to the core member functions has two
117advantages. First, there is no possibility for the user to accidently
118use a member function of the iterator when a member of the value_type
119was intended. This has been an issue with smart pointer
120implementations in the past. The second and main advantage is that
121library implementers can freely exchange a hand-rolled iterator
122implementation for one based on `iterator_facade` without fear of
123breaking code that was accessing the public core member functions
124directly.
125
126In a naive implementation, keeping the derived class' core member
127functions private would require it to grant friendship to
128`iterator_facade` and each of the seven operators. In order to
129reduce the burden of limiting access, `iterator_core_access` is
130provided, a class that acts as a gateway to the core member functions
131in the derived iterator class. The author of the derived class only
132needs to grant friendship to `iterator_core_access` to make his core
133member functions available to the library.
134
135
136`iterator_core_access` will be typically implemented as an empty
137class containing only private static member functions which invoke the
138iterator core member functions. There is, however, no need to
139standardize the gateway protocol. Note that even if
140`iterator_core_access` used public member functions it would not
141open a safety loophole, as every core member function preserves the
142invariants of the iterator.
143
144[h2 `operator[]`]
145
146The indexing operator for a generalized iterator presents special
147challenges. A random access iterator's `operator[]` is only
148required to return something convertible to its `value_type`.
149Requiring that it return an lvalue would rule out currently-legal
150random-access iterators which hold the referenced value in a data
151member (e.g. |counting|_), because `*(p+n)` is a reference
152into the temporary iterator `p+n`, which is destroyed when
153`operator[]` returns.
154
155.. |counting| replace:: `counting_iterator`
156
157Writable iterators built with `iterator_facade` implement the
158semantics required by the preferred resolution to `issue 299`_ and
159adopted by proposal n1550_: the result of `p[n]` is an object
160convertible to the iterator's `value_type`, and `p[n] = x` is
161equivalent to `*(p + n) = x` (Note: This result object may be
162implemented as a proxy containing a copy of `p+n`). This approach
163will work properly for any random-access iterator regardless of the
164other details of its implementation. A user who knows more about
165the implementation of her iterator is free to implement an
166`operator[]` that returns an lvalue in the derived iterator
167class; it will hide the one supplied by `iterator_facade` from
168clients of her iterator.
169
170.. _n1550: http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1550.htm
171
172.. _`issue 299`: http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#299
173
174.. _`operator arrow`:
175
176[h2 `operator->`]
177
178The `reference` type of a readable iterator (and today's input
179iterator) need not in fact be a reference, so long as it is
180convertible to the iterator's `value_type`. When the `value_type`
181is a class, however, it must still be possible to access members
182through `operator->`. Therefore, an iterator whose `reference`
183type is not in fact a reference must return a proxy containing a copy
184of the referenced value from its `operator->`.
185
186The return types for `iterator_facade`\ 's `operator->` and
187`operator[]` are not explicitly specified. Instead, those types
188are described in terms of a set of requirements, which must be
189satisfied by the `iterator_facade` implementation.
190
191.. [Cop95] [Coplien, 1995] Coplien, J., Curiously Recurring Template
192 Patterns, C++ Report, February 1995, pp. 24-27.
193
194[section:facade_reference Reference]
195
196 template <
197 class Derived
198 , class Value
199 , class CategoryOrTraversal
200 , class Reference = Value&
201 , class Difference = ptrdiff_t
202 >
203 class iterator_facade {
204 public:
205 typedef remove_const<Value>::type value_type;
206 typedef Reference reference;
207 typedef Value\* pointer;
208 typedef Difference difference_type;
209 typedef /* see below__ \*/ iterator_category;
210
211 reference operator\*() const;
212 /* see below__ \*/ operator->() const;
213 /* see below__ \*/ operator[](difference_type n) const;
214 Derived& operator++();
215 Derived operator++(int);
216 Derived& operator--();
217 Derived operator--(int);
218 Derived& operator+=(difference_type n);
219 Derived& operator-=(difference_type n);
220 Derived operator-(difference_type n) const;
221 protected:
222 typedef iterator_facade iterator_facade\_;
223 };
224
225 // Comparison operators
226 template <class Dr1, class V1, class TC1, class R1, class D1,
227 class Dr2, class V2, class TC2, class R2, class D2>
228 typename enable_if_interoperable<Dr1,Dr2,bool>::type // exposition
229 operator ==(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
230 iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
231
232 template <class Dr1, class V1, class TC1, class R1, class D1,
233 class Dr2, class V2, class TC2, class R2, class D2>
234 typename enable_if_interoperable<Dr1,Dr2,bool>::type
235 operator !=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
236 iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
237
238 template <class Dr1, class V1, class TC1, class R1, class D1,
239 class Dr2, class V2, class TC2, class R2, class D2>
240 typename enable_if_interoperable<Dr1,Dr2,bool>::type
241 operator <(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
242 iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
243
244 template <class Dr1, class V1, class TC1, class R1, class D1,
245 class Dr2, class V2, class TC2, class R2, class D2>
246 typename enable_if_interoperable<Dr1,Dr2,bool>::type
247 operator <=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
248 iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
249
250 template <class Dr1, class V1, class TC1, class R1, class D1,
251 class Dr2, class V2, class TC2, class R2, class D2>
252 typename enable_if_interoperable<Dr1,Dr2,bool>::type
253 operator >(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
254 iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
255
256 template <class Dr1, class V1, class TC1, class R1, class D1,
257 class Dr2, class V2, class TC2, class R2, class D2>
258 typename enable_if_interoperable<Dr1,Dr2,bool>::type
259 operator >=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
260 iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
261
262 // Iterator difference
263 template <class Dr1, class V1, class TC1, class R1, class D1,
264 class Dr2, class V2, class TC2, class R2, class D2>
265 /* see below__ \*/
266 operator-(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
267 iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
268
269 // Iterator addition
270 template <class Dr, class V, class TC, class R, class D>
271 Derived operator+ (iterator_facade<Dr,V,TC,R,D> const&,
272 typename Derived::difference_type n);
273
274 template <class Dr, class V, class TC, class R, class D>
275 Derived operator+ (typename Derived::difference_type n,
276 iterator_facade<Dr,V,TC,R,D> const&);
277
278__ `iterator category`_
279
280__ `operator arrow`_
281
282__ brackets_
283
284__ minus_
285
286.. _`iterator category`:
287
288The `iterator_category` member of `iterator_facade` is
289
290.. parsed-literal::
291
292 *iterator-category*\ (CategoryOrTraversal, reference, value_type)
293
294where *iterator-category* is defined as follows:
295
296.. include:: facade_iterator_category.rst
297
298The `enable_if_interoperable` template used above is for exposition
299purposes. The member operators should only be in an overload set
300provided the derived types `Dr1` and `Dr2` are interoperable,
301meaning that at least one of the types is convertible to the other. The
302`enable_if_interoperable` approach uses SFINAE to take the operators
303out of the overload set when the types are not interoperable.
304The operators should behave *as-if* `enable_if_interoperable`
305were defined to be:
306
307 template <bool, typename> enable_if_interoperable_impl
308 {};
309
310 template <typename T> enable_if_interoperable_impl<true,T>
311 { typedef T type; };
312
313 template<typename Dr1, typename Dr2, typename T>
314 struct enable_if_interoperable
315 : enable_if_interoperable_impl<
316 is_convertible<Dr1,Dr2>::value || is_convertible<Dr2,Dr1>::value
317 , T
318 >
319 {};
320
321
322[h2 Requirements]
323
324The following table describes the typical valid expressions on
325`iterator_facade`\ 's `Derived` parameter, depending on the
326iterator concept(s) it will model. The operations in the first
327column must be made accessible to member functions of class
328`iterator_core_access`. In addition,
329`static_cast<Derived*>(iterator_facade*)` shall be well-formed.
330
331In the table below, `F` is `iterator_facade<X,V,C,R,D>`, `a` is an
332object of type `X`, `b` and `c` are objects of type `const X`,
333`n` is an object of `F::difference_type`, `y` is a constant
334object of a single pass iterator type interoperable with `X`, and `z`
335is a constant object of a random access traversal iterator type
336interoperable with `X`.
337
338.. _`core operations`:
339
340.. topic:: `iterator_facade` Core Operations
341
342[table Core Operations
343 [
344 [Expression]
345 [Return Type]
346 [Assertion/Note]
347 [Used to implement Iterator Concept(s)]
348 ]
349 [
350 [`c.dereference()`]
351 [`F::reference`]
352 []
353 [Readable Iterator, Writable Iterator]
354 ]
355 [
356 [`c.equal(y)`]
357 [convertible to bool]
358 [true iff `c` and `y` refer to the same position]
359 [Single Pass Iterator]
360 ]
361 [
362 [`a.increment()`]
363 [unused]
364 []
365 [Incrementable Iterator]
366 ]
367 [
368 [`a.decrement()`]
369 [unused]
370 []
371 [Bidirectional Traversal Iterator]
372 ]
373 [
374 [`a.advance(n)`]
375 [unused]
376 []
377 [Random Access Traversal Iterator]
378 ]
379 [
380 [`c.distance_to(z)`]
381 [convertible to `F::difference_type`]
382 [equivalent to `distance(c, X(z))`.]
383 [Random Access Traversal Iterator]
384 ]
385]
386
387[h2 Operations]
388
389The operations in this section are described in terms of operations on
390the core interface of `Derived` which may be inaccessible
391(i.e. private). The implementation should access these operations
392through member functions of class `iterator_core_access`.
393
394 reference operator*() const;
395
396[*Returns:] `static_cast<Derived const*>(this)->dereference()`
397
398 operator->() const; (see below__)
399
400__ `operator arrow`_
401
402[*Returns:] If `reference` is a reference type, an object of type `pointer` equal to: `&static_cast<Derived const*>(this)->dereference()`
403Otherwise returns an object of unspecified type such that,
404`(*static_cast<Derived const*>(this))->m` is equivalent to `(w = **static_cast<Derived const*>(this),
405w.m)` for some temporary object `w` of type `value_type`.
406
407.. _brackets:
408
409 *unspecified* operator[](difference_type n) const;
410
411[*Returns:] an object convertible to `value_type`. For constant
412 objects `v` of type `value_type`, and `n` of type
413 `difference_type`, `(*this)[n] = v` is equivalent to
414 `*(*this + n) = v`, and `static_cast<value_type
415 const&>((*this)[n])` is equivalent to
416 `static_cast<value_type const&>(*(*this + n))`
417
418 Derived& operator++();
419
420[*Effects:]
421
422 static_cast<Derived*>(this)->increment();
423 return *static_cast<Derived*>(this);
424
425 Derived operator++(int);
426
427[*Effects:]
428
429 Derived tmp(static_cast<Derived const*>(this));
430 ++*this;
431 return tmp;
432
433 Derived& operator--();
434
435[*Effects:]
436
437 static_cast<Derived*>(this)->decrement();
438 return *static_cast<Derived*>(this);
439
440 Derived operator--(int);
441
442[*Effects:]
443
444 Derived tmp(static_cast<Derived const*>(this));
445 --*this;
446 return tmp;
447
448
449 Derived& operator+=(difference_type n);
450
451[*Effects:]
452
453 static_cast<Derived*>(this)->advance(n);
454 return *static_cast<Derived*>(this);
455
456
457 Derived& operator-=(difference_type n);
458
459[*Effects:]
460
461 static_cast<Derived*>(this)->advance(-n);
462 return *static_cast<Derived*>(this);
463
464
465 Derived operator-(difference_type n) const;
466
467[*Effects:]
468
469 Derived tmp(static_cast<Derived const*>(this));
470 return tmp -= n;
471
472 template <class Dr, class V, class TC, class R, class D>
473 Derived operator+ (iterator_facade<Dr,V,TC,R,D> const&,
474 typename Derived::difference_type n);
475
476 template <class Dr, class V, class TC, class R, class D>
477 Derived operator+ (typename Derived::difference_type n,
478 iterator_facade<Dr,V,TC,R,D> const&);
479
480[*Effects:]
481
482 Derived tmp(static_cast<Derived const*>(this));
483 return tmp += n;
484
485 template <class Dr1, class V1, class TC1, class R1, class D1,
486 class Dr2, class V2, class TC2, class R2, class D2>
487 typename enable_if_interoperable<Dr1,Dr2,bool>::type
488 operator ==(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
489 iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
490
491[*Returns:]
492
493[pre
494 if `is_convertible<Dr2,Dr1>::value`
495
496 then
497 `((Dr1 const&)lhs).equal((Dr2 const&)rhs)`.
498
499 Otherwise,
500 `((Dr2 const&)rhs).equal((Dr1 const&)lhs)`.
501]
502
503
504 template <class Dr1, class V1, class TC1, class R1, class D1,
505 class Dr2, class V2, class TC2, class R2, class D2>
506 typename enable_if_interoperable<Dr1,Dr2,bool>::type
507 operator !=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
508 iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
509
510[*Returns:]
511
512[pre
513 if `is_convertible<Dr2,Dr1>::value`
514
515 then
516 `!((Dr1 const&)lhs).equal((Dr2 const&)rhs)`.
517
518 Otherwise,
519 `!((Dr2 const&)rhs).equal((Dr1 const&)lhs)`.
520]
521
522
523 template <class Dr1, class V1, class TC1, class R1, class D1,
524 class Dr2, class V2, class TC2, class R2, class D2>
525 typename enable_if_interoperable<Dr1,Dr2,bool>::type
526 operator <(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
527 iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
528
529[*Returns:]
530
531[pre
532 if `is_convertible<Dr2,Dr1>::value`
533
534 then
535 `((Dr1 const&)lhs).distance_to((Dr2 const&)rhs) < 0`.
536
537 Otherwise,
538 `((Dr2 const&)rhs).distance_to((Dr1 const&)lhs) > 0`.
539]
540
541
542 template <class Dr1, class V1, class TC1, class R1, class D1,
543 class Dr2, class V2, class TC2, class R2, class D2>
544 typename enable_if_interoperable<Dr1,Dr2,bool>::type
545 operator <=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
546 iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
547
548[*Returns:]
549
550[pre
551 if `is_convertible<Dr2,Dr1>::value`
552
553 then
554 `((Dr1 const&)lhs).distance_to((Dr2 const&)rhs) <= 0`.
555
556 Otherwise,
557 `((Dr2 const&)rhs).distance_to((Dr1 const&)lhs) >= 0`.
558]
559
560
561 template <class Dr1, class V1, class TC1, class R1, class D1,
562 class Dr2, class V2, class TC2, class R2, class D2>
563 typename enable_if_interoperable<Dr1,Dr2,bool>::type
564 operator >(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
565 iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
566
567[*Returns:]
568
569[pre
570 if `is_convertible<Dr2,Dr1>::value`
571
572 then
573 `((Dr1 const&)lhs).distance_to((Dr2 const&)rhs) > 0`.
574
575 Otherwise,
576 `((Dr2 const&)rhs).distance_to((Dr1 const&)lhs) < 0`.
577]
578
579
580 template <class Dr1, class V1, class TC1, class R1, class D1,
581 class Dr2, class V2, class TC2, class R2, class D2>
582 typename enable_if_interoperable<Dr1,Dr2,bool>::type
583 operator >=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
584 iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
585
586[*Returns:]
587
588[pre
589 if `is_convertible<Dr2,Dr1>::value`
590
591 then
592 `((Dr1 const&)lhs).distance_to((Dr2 const&)rhs) >= 0`.
593
594 Otherwise,
595 `((Dr2 const&)rhs).distance_to((Dr1 const&)lhs) <= 0`.
596]
597
598.. _minus:
599
600
601 template <class Dr1, class V1, class TC1, class R1, class D1,
602 class Dr2, class V2, class TC2, class R2, class D2>
603 typename enable_if_interoperable<Dr1,Dr2,difference>::type
604 operator -(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
605 iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
606
607[*Return Type:]
608
609[pre
610 if `is_convertible<Dr2,Dr1>::value`
611
612 then
613 `difference` shall be
614 `iterator_traits<Dr1>::difference_type`.
615
616 Otherwise
617 `difference` shall be `iterator_traits<Dr2>::difference_type`
618]
619
620[*Returns:]
621
622[pre
623 if `is_convertible<Dr2,Dr1>::value`
624
625 then
626 `-((Dr1 const&)lhs).distance_to((Dr2 const&)rhs)`.
627
628 Otherwise,
629 `((Dr2 const&)rhs).distance_to((Dr1 const&)lhs)`.
630]
631
632
633[endsect]
634
635[include facade_tutorial.qbk]
636
637[endsect]