diff --git a/doc/.cvsignore b/doc/.cvsignore deleted file mode 100755 index 59a4657..0000000 --- a/doc/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -GNUmakefile diff --git a/doc/BidirectionalTraversal.html b/doc/BidirectionalTraversal.html deleted file mode 100644 index 5bc8342..0000000 --- a/doc/BidirectionalTraversal.html +++ /dev/null @@ -1,351 +0,0 @@ - - - -
- - -A class or built-in type X models the Bidirectional Traversal -concept if, in addition to X meeting the requirements of Forward -Traversal Iterator, the following expressions are valid and respect -the stated semantics.
-Bidirectional Traversal Iterator Requirements (in addition to Forward Traversal -Iterator) | -||
---|---|---|
Expression | -Return Type | -Assertion/Semantics / -Pre-/Post-condition | -
--r | -X& | -pre: there exists -s such that r -== ++s. post: -s is -dereferenceable. ---(++r) == r. ---r == --s -implies r == -s. &r == &--r. | -
r-- | -convertible to const X& | --{ - X tmp = r; - --r; - return tmp; -} -- |
-
iterator_traversal<X>::type | -Convertible to -bidirectional_traversal_tag | -- |
A class or built-in type X models the Forward Traversal -concept if, in addition to X meeting the requirements of Default -Constructible and Single Pass Iterator, the following expressions are -valid and respect the stated semantics.
-Forward Traversal Iterator Requirements (in addition to Default Constructible and Single Pass Iterator) | -||
---|---|---|
Expression | -Return Type | -Assertion/Note | -
X u; | -X& | -note: u may have a -singular value. | -
++r | -X& | -r == s and r is -dereferenceable implies -++r == ++s. | -
iterator_traits<X>::difference_type | -A signed integral type representing -the distance between iterators | -- |
iterator_traversal<X>::type | -Convertible to -forward_traversal_tag | -- |
A class or built-in type X models the Incrementable Iterator -concept if, in addition to X being Assignable and Copy -Constructible, the following expressions are valid and respect the -stated semantics.
-Incrementable Iterator Requirements (in addition to Assignable, Copy Constructible) | -||
---|---|---|
Expression | -Return Type | -Assertion/Semantics | -
++r | -X& | -&r == &++r | -
r++ | -X | --{ - X tmp = r; - ++r; - return tmp; -} -- |
-
iterator_traversal<X>::type | -Convertible to -incrementable_traversal_tag | -- |
The Lvalue Iterator concept adds the requirement that the return -type of operator* type be a reference to the value type of the -iterator.
-Lvalue Iterator Requirements | -||
---|---|---|
Expression | -Return Type | -Note/Assertion | -
*a | -T& | -T is cv -iterator_traits<X>::value_type -where cv is an optional -cv-qualification. -pre: a is -dereferenceable. If a -== b then *a is -equivalent to *b. | -
A class or built-in type X models the Random Access Traversal -concept if the following expressions are valid and respect the stated -semantics. In the table below, Distance is -iterator_traits<X>::difference_type and n represents a -constant object of type Distance.
-Random Access Traversal Iterator Requirements (in addition to Bidirectional Traversal) | -|||
---|---|---|---|
Expression | -Return Type | -Operational Semantics | -Assertion/ -Precondition | -
r += n | -X& | --{ - Distance m = n; - if (m >= 0) - while (m--) - ++r; - else - while (m++) - --r; - return r; -} -- |
-- |
a + n, n + a | -X | -{ X tmp = a; return tmp -+= n; } | -- |
r -= n | -X& | -return r += -n | -- |
a - n | -X | -{ X tmp = a; return tmp --= n; } | -- |
b - a | -Distance | -a < b ? distance(a,b) -: -distance(b,a) | -pre: there exists a -value n of -Distance such that -a + n == b. b -== a + (b - a). | -
a[n] | -convertible to T | -*(a + n) | -pre: a is a Readable -Iterator | -
a[n] = v | -convertible to T | -*(a + n) = v | -pre: a is a Writable -iterator | -
a < b | -convertible to bool | -b - a > 0 | -< is a total -ordering relation | -
a > b | -convertible to bool | -b < a | -> is a total -ordering relation | -
a >= b | -convertible to bool | -!(a < b) | -- |
a <= b | -convertible to bool | -!(a > b) | -- |
iterator_traversal<X>::type | -Convertible to -random_access_traversal_tag | -- | - |
A class or built-in type X models the Readable Iterator concept -for value type T if, in addition to X being Assignable and -Copy Constructible, the following expressions are valid and respect -the stated semantics. U is the type of any specified member of -type T.
-Readable Iterator Requirements (in addition to Assignable and Copy Constructible) | -||
---|---|---|
Expression | -Return Type | -Note/Precondition | -
iterator_traits<X>::value_type | -T | -Any non-reference, -non-cv-qualified type | -
*a | -Convertible to T | -
|
-
a->m | -U& | -pre: pre: (*a).m is well-defined. Equivalent to (*a).m. | -
A class or built-in type X models the Single Pass Iterator -concept if the following expressions are valid and respect the stated -semantics.
-Single Pass Iterator Requirements (in addition to Incrementable Iterator and Equality -Comparable) | -||
---|---|---|
Expression | -Return Type | -Assertion/Semantics / -Pre-/Post-condition | -
++r | -X& | -pre: r is -dereferenceable; post: -r is dereferenceable or -r is past-the-end | -
a == b | -convertible to bool | -== is an equivalence -relation over its domain | -
a != b | -convertible to bool | -!(a == b) | -
iterator_traversal<X>::type | -Convertible to -single_pass_traversal_tag | -- |
A class or built-in type X models the Swappable Iterator concept -if, in addition to X being Copy Constructible, the following -expressions are valid and respect the stated semantics.
-Swappable Iterator Requirements (in addition to Copy Constructible) | -||
---|---|---|
Expression | -Return Type | -Postcondition | -
iter_swap(a, b) | -void | -the pointed to values are -exchanged | -
A class or built-in type X models the Writable Iterator concept -if, in addition to X being Copy Constructible, the following -expressions are valid and respect the stated semantics. Writable -Iterators have an associated set of value types.
-Writable Iterator Requirements (in addition to Copy Constructible) | -||
---|---|---|
Expression | -Return Type | -Precondition | -
*a = o | -- | pre: The type of o -is in the set of -value types of X | -
Author: | -David Abrahams, Jeremy Siek, Thomas Witt |
---|---|
Contact: | -dave@boost-consulting.com, jsiek@osl.iu.edu, witt@ive.uni-hannover.de |
Organization: | -Boost Consulting, Indiana University Open Systems -Lab, University of Hanover Institute for Transport -Railway Operation and Construction |
Date: | -2004-11-01 |
Copyright: | -Copyright David Abrahams, Jeremy Siek, and Thomas Witt 2003. |
abstract: | How would you fill up a vector with the numbers zero -through one hundred using std::copy()? The only iterator -operation missing from builtin integer types is an -operator*() that returns the current value of the integer. -The counting iterator adaptor adds this crucial piece of -functionality to whatever type it wraps. One can use the -counting iterator adaptor not only with integer types, but with -any incrementable type. - - - -counting_iterator adapts an object by adding an operator* that -returns the current value of the object. All other iterator operations -are forwarded to the adapted object. - |
-
---|
-template < - class Incrementable - , class CategoryOrTraversal = use_default - , class Difference = use_default -> -class counting_iterator -{ -public: - typedef Incrementable value_type; - typedef const Incrementable& reference; - typedef const Incrementable* pointer; - typedef /* see below */ difference_type; - typedef /* see below */ iterator_category; - - counting_iterator(); - counting_iterator(counting_iterator const& rhs); - explicit counting_iterator(Incrementable x); - Incrementable const& base() const; - reference operator*() const; - counting_iterator& operator++(); - counting_iterator& operator--(); -private: - Incrementable m_inc; // exposition -}; --
If the Difference argument is use_default then -difference_type is an unspecified signed integral -type. Otherwise difference_type is Difference.
-iterator_category is determined according to the following -algorithm:
--if (CategoryOrTraversal is not use_default) - return CategoryOrTraversal -else if (numeric_limits<Incrementable>::is_specialized) - return iterator-category( - random_access_traversal_tag, Incrementable, const Incrementable&) -else - return iterator-category( - iterator_traversal<Incrementable>::type, - Incrementable, const Incrementable&) --
The Incrementable argument shall be Copy Constructible and Assignable.
-If iterator_category is convertible to forward_iterator_tag -or forward_traversal_tag, the following must be well-formed:
--Incrementable i, j; -++i; // pre-increment -i == j; // operator equal --
If iterator_category is convertible to -bidirectional_iterator_tag or bidirectional_traversal_tag, -the following expression must also be well-formed:
----i --
If iterator_category is convertible to -random_access_iterator_tag or random_access_traversal_tag, -the following must must also be valid:
--counting_iterator::difference_type n; -i += n; -n = i - j; -i < j; --
Specializations of counting_iterator model Readable Lvalue -Iterator. In addition, they model the concepts corresponding to the -iterator tags to which their iterator_category is convertible. -Also, if CategoryOrTraversal is not use_default then -counting_iterator models the concept corresponding to the iterator -tag CategoryOrTraversal. Otherwise, if -numeric_limits<Incrementable>::is_specialized, then -counting_iterator models Random Access Traversal Iterator. -Otherwise, counting_iterator models the same iterator traversal -concepts modeled by Incrementable.
-counting_iterator<X,C1,D1> is interoperable with -counting_iterator<Y,C2,D2> if and only if X is -interoperable with Y.
-In addition to the operations required by the concepts modeled by -counting_iterator, counting_iterator provides the following -operations.
-counting_iterator();
-Requires: | Incrementable is Default Constructible. | -
---|---|
Effects: | Default construct the member m_inc. | -
counting_iterator(counting_iterator const& rhs);
-Effects: | Construct member m_inc from rhs.m_inc. | -
---|
explicit counting_iterator(Incrementable x);
-Effects: | Construct member m_inc from x. | -
---|
reference operator*() const;
-Returns: | m_inc | -
---|
counting_iterator& operator++();
-Effects: | ++m_inc | -
---|---|
Returns: | *this | -
counting_iterator& operator--();
-Effects: | --m_inc | -
---|---|
Returns: | *this | -
Incrementable const& base() const;
-Returns: | m_inc | -
---|
-template <class Incrementable> -counting_iterator<Incrementable> make_counting_iterator(Incrementable x); --
Returns: | An instance of counting_iterator<Incrementable> -with current constructed from x. | -
---|
This example fills an array with numbers and a second array with -pointers into the first array, using counting_iterator for both -tasks. Finally indirect_iterator is used to print out the numbers -into the first array via indirection through the second array.
--int N = 7; -std::vector<int> numbers; -typedef std::vector<int>::iterator n_iter; -std::copy(boost::counting_iterator<int>(0), - boost::counting_iterator<int>(N), - std::back_inserter(numbers)); - -std::vector<std::vector<int>::iterator> pointers; -std::copy(boost::make_counting_iterator(numbers.begin()), - boost::make_counting_iterator(numbers.end()), - std::back_inserter(pointers)); - -std::cout << "indirectly printing out the numbers from 0 to " - << N << std::endl; -std::copy(boost::make_indirect_iterator(pointers.begin()), - boost::make_indirect_iterator(pointers.end()), - std::ostream_iterator<int>(std::cout, " ")); -std::cout << std::endl; --
The output is:
--indirectly printing out the numbers from 0 to 7 -0 1 2 3 4 5 6 --
The source code for this example can be found here.
-Author: | -David Abrahams, Jeremy Siek, Thomas Witt |
---|---|
Contact: | -dave@boost-consulting.com, jsiek@osl.iu.edu, witt@styleadvisor.com |
Organization: | -Boost Consulting, Indiana University Open Systems -Lab, Zephyr Associates, Inc. |
Date: | -2004-11-01 |
Number: | This is a revised version of N1530=03-0113, which was -accepted for Technical Report 1 by the C++ standard -committee's library working group. | -
copyright: | Copyright David Abrahams, Jeremy Siek, and Thomas Witt 2003. | -
---|
abstract: | We propose a set of class templates that help programmers -build standard-conforming iterators, both from scratch and -by adapting other iterators. | -
---|
Iterators play an important role in modern C++ programming. The -iterator is the central abstraction of the algorithms of the Standard -Library, allowing algorithms to be re-used in in a wide variety of -contexts. The C++ Standard Library contains a wide variety of useful -iterators. Every one of the standard containers comes with constant -and mutable iterators [2], and also reverse versions of those -same iterators which traverse the container in the opposite direction. -The Standard also supplies istream_iterator and -ostream_iterator for reading from and writing to streams, -insert_iterator, front_insert_iterator and -back_insert_iterator for inserting elements into containers, and -raw_storage_iterator for initializing raw memory [7].
-Despite the many iterators supplied by the Standard Library, obvious -and useful iterators are missing, and creating new iterator types is -still a common task for C++ programmers. The literature documents -several of these, for example line_iterator [3] and Constant_iterator -[9]. The iterator abstraction is so powerful that we expect -programmers will always need to invent new iterator types.
-Although it is easy to create iterators that almost conform to the -standard, the iterator requirements contain subtleties which can make -creating an iterator which actually conforms quite difficult. -Further, the iterator interface is rich, containing many operators -that are technically redundant and tedious to implement. To automate -the repetitive work of constructing iterators, we propose -iterator_facade, an iterator base class template which provides -the rich interface of standard iterators and delegates its -implementation to member functions of the derived class. In addition -to reducing the amount of code necessary to create an iterator, the -iterator_facade also provides compile-time error detection. -Iterator implementation mistakes that often go unnoticed are turned -into compile-time errors because the derived class implementation must -match the expectations of the iterator_facade.
-A common pattern of iterator construction is the adaptation of one -iterator to form a new one. The functionality of an iterator is -composed of four orthogonal aspects: traversal, indirection, equality -comparison and distance measurement. Adapting an old iterator to -create a new one often saves work because one can reuse one aspect of -functionality while redefining the other. For example, the Standard -provides reverse_iterator, which adapts any Bidirectional Iterator -by inverting its direction of traversal. As with plain iterators, -iterator adaptors defined outside the Standard have become commonplace -in the literature:
-[1] | We use the term concept to mean a set of requirements -that a type must satisfy to be used with a particular template -parameter. |
[2] | The term mutable iterator refers to iterators over objects that -can be changed by assigning to the dereferenced iterator, while -constant iterator refers to iterators over objects that cannot be -modified. |
To fulfill the need for constructing adaptors, we propose the -iterator_adaptor class template. Instantiations of -iterator_adaptor serve as a base classes for new iterators, -providing the default behavior of forwarding all operations to the -underlying iterator. The user can selectively replace these features -in the derived iterator class. This proposal also includes a number -of more specialized adaptors, such as the transform_iterator that -applies some user-specified function during the dereference of the -iterator.
-This proposal is purely an addition to the C++ standard library. -However, note that this proposal relies on the proposal for New -Iterator Concepts.
-This proposal is formulated in terms of the new iterator concepts -as proposed in n1550, since user-defined and especially adapted -iterators suffer from the well known categorization problems that are -inherent to the current iterator categories.
-This proposal does not strictly depend on proposal n1550, as there -is a direct mapping between new and old categories. This proposal -could be reformulated using this mapping if n1550 was not accepted.
-The question of iterator interoperability is poorly addressed in the -current standard. There are currently two defect reports that are -concerned with interoperability issues.
-Issue 179 concerns the fact that mutable container iterator types -are only required to be convertible to the corresponding constant -iterator types, but objects of these types are not required to -interoperate in comparison or subtraction expressions. This situation -is tedious in practice and out of line with the way built in types -work. This proposal implements the proposed resolution to issue -179, as most standard library implementations do nowadays. In other -words, if an iterator type A has an implicit or user defined -conversion to an iterator type B, the iterator types are interoperable -and the usual set of operators are available.
-Issue 280 concerns the current lack of interoperability between -reverse iterator types. The proposed new reverse_iterator template -fixes the issues raised in 280. It provides the desired -interoperability without introducing unwanted overloads.
-While the iterator interface is rich, there is a core subset of the -interface that is necessary for all the functionality. We have -identified the following core behaviors for iterators:
-In addition to the behaviors listed above, the core interface elements -include the associated types exposed through iterator traits: -value_type, reference, difference_type, and -iterator_category.
-Iterator facade uses the Curiously Recurring Template -Pattern (CRTP) [Cop95] so that the user can specify the behavior -of iterator_facade in a derived class. Former designs used -policy objects to specify the behavior, but that approach was -discarded for several reasons:
----
-- the creation and eventual copying of the policy object may create -overhead that can be avoided with the current approach.
-- The policy object approach does not allow for custom constructors -on the created iterator types, an essential feature if -iterator_facade should be used in other library -implementations.
-- Without the use of CRTP, the standard requirement that an -iterator's operator++ returns the iterator type itself -would mean that all iterators built with the library would -have to be specializations of iterator_facade<...>, rather -than something more descriptive like -indirect_iterator<T*>. Cumbersome type generator -metafunctions would be needed to build new parameterized -iterators, and a separate iterator_adaptor layer would be -impossible.
-
The user of iterator_facade derives his iterator class from a -specialization of iterator_facade and passes the derived -iterator class as iterator_facade's first template parameter. -The order of the other template parameters have been carefully -chosen to take advantage of useful defaults. For example, when -defining a constant lvalue iterator, the user can pass a -const-qualified version of the iterator's value_type as -iterator_facade's Value parameter and omit the -Reference parameter which follows.
-The derived iterator class must define member functions implementing -the iterator's core behaviors. The following table describes -expressions which are required to be valid depending on the category -of the derived iterator type. These member functions are described -briefly below and in more detail in the iterator facade -requirements.
--- --
-- - -- - - - - Expression -Effects -- i.dereference() -Access the value referred to -- i.equal(j) -Compare for equality with j -- i.increment() -Advance by one position -- i.decrement() -Retreat by one position -- i.advance(n) -Advance by n positions -- - i.distance_to(j) -Measure the distance to j -
In addition to implementing the core interface functions, an iterator -derived from iterator_facade typically defines several -constructors. To model any of the standard iterator concepts, the -iterator must at least have a copy constructor. Also, if the iterator -type X is meant to be automatically interoperate with another -iterator type Y (as with constant and mutable iterators) then -there must be an implicit conversion from X to Y or from Y -to X (but not both), typically implemented as a conversion -constructor. Finally, if the iterator is to model Forward Traversal -Iterator or a more-refined iterator concept, a default constructor is -required.
-iterator_facade and the operator implementations need to be able -to access the core member functions in the derived class. Making the -core member functions public would expose an implementation detail to -the user. The design used here ensures that implementation details do -not appear in the public interface of the derived iterator type.
-Preventing direct access to the core member functions has two -advantages. First, there is no possibility for the user to accidently -use a member function of the iterator when a member of the value_type -was intended. This has been an issue with smart pointer -implementations in the past. The second and main advantage is that -library implementers can freely exchange a hand-rolled iterator -implementation for one based on iterator_facade without fear of -breaking code that was accessing the public core member functions -directly.
-In a naive implementation, keeping the derived class' core member -functions private would require it to grant friendship to -iterator_facade and each of the seven operators. In order to -reduce the burden of limiting access, iterator_core_access is -provided, a class that acts as a gateway to the core member functions -in the derived iterator class. The author of the derived class only -needs to grant friendship to iterator_core_access to make his core -member functions available to the library.
- - -iterator_core_access will be typically implemented as an empty -class containing only private static member functions which invoke the -iterator core member functions. There is, however, no need to -standardize the gateway protocol. Note that even if -iterator_core_access used public member functions it would not -open a safety loophole, as every core member function preserves the -invariants of the iterator.
-The indexing operator for a generalized iterator presents special -challenges. A random access iterator's operator[] is only -required to return something convertible to its value_type. -Requiring that it return an lvalue would rule out currently-legal -random-access iterators which hold the referenced value in a data -member (e.g. counting_iterator), because *(p+n) is a reference -into the temporary iterator p+n, which is destroyed when -operator[] returns.
-Writable iterators built with iterator_facade implement the -semantics required by the preferred resolution to issue 299 and -adopted by proposal n1550: the result of p[n] is an object -convertible to the iterator's value_type, and p[n] = x is -equivalent to *(p + n) = x (Note: This result object may be -implemented as a proxy containing a copy of p+n). This approach -will work properly for any random-access iterator regardless of the -other details of its implementation. A user who knows more about -the implementation of her iterator is free to implement an -operator[] that returns an lvalue in the derived iterator -class; it will hide the one supplied by iterator_facade from -clients of her iterator.
-The reference type of a readable iterator (and today's input -iterator) need not in fact be a reference, so long as it is -convertible to the iterator's value_type. When the value_type -is a class, however, it must still be possible to access members -through operator->. Therefore, an iterator whose reference -type is not in fact a reference must return a proxy containing a copy -of the referenced value from its operator->.
-The return types for iterator_facade's operator-> and -operator[] are not explicitly specified. Instead, those types -are described in terms of a set of requirements, which must be -satisfied by the iterator_facade implementation.
-[Cop95] | [Coplien, 1995] Coplien, J., Curiously Recurring Template -Patterns, C++ Report, February 1995, pp. 24-27. |
The iterator_adaptor class template adapts some Base [3] -type to create a new iterator. Instantiations of iterator_adaptor -are derived from a corresponding instantiation of iterator_facade -and implement the core behaviors in terms of the Base type. In -essence, iterator_adaptor merely forwards all operations to an -instance of the Base type, which it stores as a member.
-[3] | The term "Base" here does not refer to a base class and is -not meant to imply the use of derivation. We have followed the lead -of the standard library, which provides a base() function to access -the underlying iterator object of a reverse_iterator adaptor. |
The user of iterator_adaptor creates a class derived from an -instantiation of iterator_adaptor and then selectively -redefines some of the core member functions described in the -iterator_facade core requirements table. The Base type need -not meet the full requirements for an iterator; it need only -support the operations used by the core interface functions of -iterator_adaptor that have not been redefined in the user's -derived class.
-Several of the template parameters of iterator_adaptor default -to use_default. This allows the -user to make use of a default parameter even when she wants to -specify a parameter later in the parameter list. Also, the -defaults for the corresponding associated types are somewhat -complicated, so metaprogramming is required to compute them, and -use_default can help to simplify the implementation. Finally, -the identity of the use_default type is not left unspecified -because specification helps to highlight that the Reference -template parameter may not always be identical to the iterator's -reference type, and will keep users from making mistakes based on -that assumption.
-This proposal also contains several examples of specialized adaptors -which were easily implemented using iterator_adaptor:
-Based on examples in the Boost library, users have generated many new -adaptors, among them a permutation adaptor which applies some -permutation to a random access iterator, and a strided adaptor, which -adapts a random access iterator by multiplying its unit of motion by a -constant factor. In addition, the Boost Graph Library (BGL) uses -iterator adaptors to adapt other graph libraries, such as LEDA [10] -and Stanford GraphBase [8], to the BGL interface (which requires C++ -Standard compliant iterators).
--struct use_default; - -struct iterator_core_access { /* implementation detail */ }; - -template < - class Derived - , class Value - , class CategoryOrTraversal - , class Reference = Value& - , class Difference = ptrdiff_t -> -class iterator_facade; - -template < - class Derived - , class Base - , class Value = use_default - , class CategoryOrTraversal = use_default - , class Reference = use_default - , class Difference = use_default -> -class iterator_adaptor; - -template < - class Iterator - , class Value = use_default - , class CategoryOrTraversal = use_default - , class Reference = use_default - , class Difference = use_default -> -class indirect_iterator; - -template <class Dereferenceable> -struct pointee; - -template <class Dereferenceable> -struct indirect_reference; - -template <class Iterator> -class reverse_iterator; - -template < - class UnaryFunction - , class Iterator - , class Reference = use_default - , class Value = use_default -> -class transform_iterator; - -template <class Predicate, class Iterator> -class filter_iterator; - -template < - class Incrementable - , class CategoryOrTraversal = use_default - , class Difference = use_default -> -class counting_iterator; - -template <class UnaryFunction> -class function_output_iterator; --
iterator_facade is a base class template that implements the -interface of standard iterators in terms of a few core functions -and associated types, to be supplied by a derived iterator class.
--template < - class Derived - , class Value - , class CategoryOrTraversal - , class Reference = Value& - , class Difference = ptrdiff_t -> -class iterator_facade { - public: - typedef remove_const<Value>::type value_type; - typedef Reference reference; - typedef Value* pointer; - typedef Difference difference_type; - typedef /* see below */ iterator_category; - - reference operator*() const; - /* see below */ operator->() const; - /* see below */ operator[](difference_type n) const; - Derived& operator++(); - Derived operator++(int); - Derived& operator--(); - Derived operator--(int); - Derived& operator+=(difference_type n); - Derived& operator-=(difference_type n); - Derived operator-(difference_type n) const; - protected: - typedef iterator_facade iterator_facade_; -}; - -// Comparison operators -template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type // exposition -operator ==(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); - -template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type -operator !=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); - -template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type -operator <(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); - -template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type -operator <=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); - -template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type -operator >(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); - -template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type -operator >=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); - -// Iterator difference -template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -/* see below */ -operator-(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); - -// Iterator addition -template <class Dr, class V, class TC, class R, class D> -Derived operator+ (iterator_facade<Dr,V,TC,R,D> const&, - typename Derived::difference_type n); - -template <class Dr, class V, class TC, class R, class D> -Derived operator+ (typename Derived::difference_type n, - iterator_facade<Dr,V,TC,R,D> const&); --
The iterator_category member of iterator_facade is
--iterator-category(CategoryOrTraversal, value_type, reference) --
where iterator-category is defined as follows:
--iterator-category(C,R,V) := - if (C is convertible to std::input_iterator_tag - || C is convertible to std::output_iterator_tag - ) - return C - - else if (C is not convertible to incrementable_traversal_tag) - the program is ill-formed - - else return a type X satisfying the following two constraints: - - 1. X is convertible to X1, and not to any more-derived - type, where X1 is defined by: - - if (R is a reference type - && C is convertible to forward_traversal_tag) - { - if (C is convertible to random_access_traversal_tag) - X1 = random_access_iterator_tag - else if (C is convertible to bidirectional_traversal_tag) - X1 = bidirectional_iterator_tag - else - X1 = forward_iterator_tag - } - else - { - if (C is convertible to single_pass_traversal_tag - && R is convertible to V) - X1 = input_iterator_tag - else - X1 = C - } - - 2. category-to-traversal(X) is convertible to the most - derived traversal tag type to which X is also - convertible, and not to any more-derived traversal tag - type. --
[Note: the intention is to allow iterator_category to be one of -the five original category tags when convertibility to one of the -traversal tags would add no information]
- - - -The enable_if_interoperable template used above is for exposition -purposes. The member operators should only be in an overload set -provided the derived types Dr1 and Dr2 are interoperable, -meaning that at least one of the types is convertible to the other. The -enable_if_interoperable approach uses SFINAE to take the operators -out of the overload set when the types are not interoperable. -The operators should behave as-if enable_if_interoperable -were defined to be:
--template <bool, typename> enable_if_interoperable_impl -{}; - -template <typename T> enable_if_interoperable_impl<true,T> -{ typedef T type; }; - -template<typename Dr1, typename Dr2, typename T> -struct enable_if_interoperable - : enable_if_interoperable_impl< - is_convertible<Dr1,Dr2>::value || is_convertible<Dr2,Dr1>::value - , T - > -{}; --
The following table describes the typical valid expressions on -iterator_facade's Derived parameter, depending on the -iterator concept(s) it will model. The operations in the first -column must be made accessible to member functions of class -iterator_core_access. In addition, -static_cast<Derived*>(iterator_facade*) shall be well-formed.
-In the table below, F is iterator_facade<X,V,C,R,D>, a is an -object of type X, b and c are objects of type const X, -n is an object of F::difference_type, y is a constant -object of a single pass iterator type interoperable with X, and z -is a constant object of a random access traversal iterator type -interoperable with X.
-iterator_facade Core Operations
-Expression | -Return Type | -Assertion/Note | -Used to implement Iterator -Concept(s) | -
---|---|---|---|
c.dereference() | -F::reference | -- | Readable Iterator, Writable -Iterator | -
c.equal(y) | -convertible to bool | -true iff c and y -refer to the same -position. | -Single Pass Iterator | -
a.increment() | -unused | -- | Incrementable Iterator | -
a.decrement() | -unused | -- | Bidirectional Traversal -Iterator | -
a.advance(n) | -unused | -- | Random Access Traversal -Iterator | -
c.distance_to(z) | -convertible to -F::difference_type | -equivalent to -distance(c, X(z)). | -Random Access Traversal -Iterator | -
The operations in this section are described in terms of operations on -the core interface of Derived which may be inaccessible -(i.e. private). The implementation should access these operations -through member functions of class iterator_core_access.
-reference operator*() const;
-Returns: | static_cast<Derived const*>(this)->dereference() | -
---|
operator->() const; (see below)
-Returns: | If reference is a reference type, an object -of type pointer equal to: --&static_cast<Derived const*>(this)->dereference() -- Otherwise returns an object of unspecified type such that, -(*static_cast<Derived const*>(this))->m is equivalent to (w = **static_cast<Derived const*>(this), -w.m) for some temporary object w of type value_type. - |
-
---|
unspecified operator[](difference_type n) const;
-Returns: | an object convertible to value_type. For constant -objects v of type value_type, and n of type -difference_type, (*this)[n] = v is equivalent to -*(*this + n) = v, and static_cast<value_type -const&>((*this)[n]) is equivalent to -static_cast<value_type const&>(*(*this + n)) | -
---|
Derived& operator++();
-Effects: | -static_cast<Derived*>(this)->increment(); -return *static_cast<Derived*>(this); -- |
-
---|
Derived operator++(int);
-Effects: | -Derived tmp(static_cast<Derived const*>(this)); -++*this; -return tmp; -- |
-
---|
Derived& operator--();
-Effects: | -static_cast<Derived*>(this)->decrement(); -return *static_cast<Derived*>(this); -- |
-
---|
Derived operator--(int);
-Effects: | -Derived tmp(static_cast<Derived const*>(this)); ---*this; -return tmp; -- |
-
---|
Derived& operator+=(difference_type n);
-Effects: | -static_cast<Derived*>(this)->advance(n); -return *static_cast<Derived*>(this); -- |
-
---|
Derived& operator-=(difference_type n);
-Effects: | -static_cast<Derived*>(this)->advance(-n); -return *static_cast<Derived*>(this); -- |
-
---|
Derived operator-(difference_type n) const;
-Effects: | -Derived tmp(static_cast<Derived const*>(this)); -return tmp -= n; -- |
-
---|
-template <class Dr, class V, class TC, class R, class D> -Derived operator+ (iterator_facade<Dr,V,TC,R,D> const&, - typename Derived::difference_type n); - -template <class Dr, class V, class TC, class R, class D> -Derived operator+ (typename Derived::difference_type n, - iterator_facade<Dr,V,TC,R,D> const&); --
Effects: | -Derived tmp(static_cast<Derived const*>(this)); -return tmp += n; -- |
-
---|
-template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type -operator ==(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); --
Returns: | if is_convertible<Dr2,Dr1>::value -
|
-
---|
-template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type -operator !=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); --
Returns: | if is_convertible<Dr2,Dr1>::value -
|
-
---|
-template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type -operator <(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); --
Returns: | if is_convertible<Dr2,Dr1>::value -
|
-
---|
-template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type -operator <=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); --
Returns: | if is_convertible<Dr2,Dr1>::value -
|
-
---|
-template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type -operator >(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); --
Returns: | if is_convertible<Dr2,Dr1>::value -
|
-
---|
-template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type -operator >=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); --
Returns: | if is_convertible<Dr2,Dr1>::value -
|
-
---|
-template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,difference>::type -operator -(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); --
Return Type: | if is_convertible<Dr2,Dr1>::value --- |
-
---|---|
Returns: | if is_convertible<Dr2,Dr1>::value -
|
-
Each specialization of the iterator_adaptor class template is derived from -a specialization of iterator_facade. The core interface functions -expected by iterator_facade are implemented in terms of the -iterator_adaptor's Base template parameter. A class derived -from iterator_adaptor typically redefines some of the core -interface functions to adapt the behavior of the Base type. -Whether the derived class models any of the standard iterator concepts -depends on the operations supported by the Base type and which -core interface functions of iterator_facade are redefined in the -Derived class.
--template < - class Derived - , class Base - , class Value = use_default - , class CategoryOrTraversal = use_default - , class Reference = use_default - , class Difference = use_default -> -class iterator_adaptor - : public iterator_facade<Derived, V', C', R', D'> // see details -{ - friend class iterator_core_access; - public: - iterator_adaptor(); - explicit iterator_adaptor(Base const& iter); - typedef Base base_type; - Base const& base() const; - protected: - typedef iterator_adaptor iterator_adaptor_; - Base const& base_reference() const; - Base& base_reference(); - private: // Core iterator interface for iterator_facade. - typename iterator_adaptor::reference dereference() const; - - template < - class OtherDerived, class OtherIterator, class V, class C, class R, class D - > - bool equal(iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D> const& x) const; - - void advance(typename iterator_adaptor::difference_type n); - void increment(); - void decrement(); - - template < - class OtherDerived, class OtherIterator, class V, class C, class R, class D - > - typename iterator_adaptor::difference_type distance_to( - iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D> const& y) const; - - private: - Base m_iterator; // exposition only -}; --
static_cast<Derived*>(iterator_adaptor*) shall be well-formed. -The Base argument shall be Assignable and Copy Constructible.
-The V', C', R', and D' parameters of the iterator_facade -used as a base class in the summary of iterator_adaptor -above are defined as follows:
--V' = if (Value is use_default) - return iterator_traits<Base>::value_type - else - return Value - -C' = if (CategoryOrTraversal is use_default) - return iterator_traversal<Base>::type - else - return CategoryOrTraversal - -R' = if (Reference is use_default) - if (Value is use_default) - return iterator_traits<Base>::reference - else - return Value& - else - return Reference - -D' = if (Difference is use_default) - return iterator_traits<Base>::difference_type - else - return Difference -- - - -
iterator_adaptor();
-Requires: | The Base type must be Default Constructible. | -
---|---|
Returns: | An instance of iterator_adaptor with -m_iterator default constructed. | -
explicit iterator_adaptor(Base const& iter);
-Returns: | An instance of iterator_adaptor with -m_iterator copy constructed from iter. | -
---|
Base const& base() const;
-Returns: | m_iterator | -
---|
Base const& base_reference() const;
-Returns: | A const reference to m_iterator. | -
---|
Base& base_reference();
-Returns: | A non-const reference to m_iterator. | -
---|
typename iterator_adaptor::reference dereference() const;
-Returns: | *m_iterator | -
---|
-template < -class OtherDerived, class OtherIterator, class V, class C, class R, class D -> -bool equal(iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D> const& x) const; --
Returns: | m_iterator == x.base() | -
---|
void advance(typename iterator_adaptor::difference_type n);
-Effects: | m_iterator += n; | -
---|
void increment();
-Effects: | ++m_iterator; | -
---|
void decrement();
-Effects: | --m_iterator; | -
---|
-template < - class OtherDerived, class OtherIterator, class V, class C, class R, class D -> -typename iterator_adaptor::difference_type distance_to( - iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D> const& y) const; --
Returns: | y.base() - m_iterator | -
---|
The enable_if_convertible<X,Y>::type expression used in -this section is for exposition purposes. The converting constructors -for specialized adaptors should be only be in an overload set provided -that an object of type X is implicitly convertible to an object of -type Y. -The signatures involving enable_if_convertible should behave -as-if enable_if_convertible were defined to be:
--template <bool> enable_if_convertible_impl -{}; - -template <> enable_if_convertible_impl<true> -{ struct type; }; - -template<typename From, typename To> -struct enable_if_convertible - : enable_if_convertible_impl<is_convertible<From,To>::value> -{}; --
If an expression other than the default argument is used to supply -the value of a function parameter whose type is written in terms -of enable_if_convertible, the program is ill-formed, no -diagnostic required.
-[Note: The enable_if_convertible approach uses SFINAE to -take the constructor out of the overload set when the types are not -implicitly convertible. -]
-indirect_iterator adapts an iterator by applying an -extra dereference inside of operator*(). For example, this -iterator adaptor makes it possible to view a container of pointers -(e.g. list<foo*>) as if it were a container of the pointed-to type -(e.g. list<foo>). indirect_iterator depends on two -auxiliary traits, pointee and indirect_reference, to -provide support for underlying iterators whose value_type is -not an iterator.
--template <class Dereferenceable> -struct pointee -{ - typedef /* see below */ type; -}; --
Requires: | For an object x of type Dereferenceable, *x -is well-formed. If ++x is ill-formed it shall neither be -ambiguous nor shall it violate access control, and -Dereferenceable::element_type shall be an accessible type. -Otherwise iterator_traits<Dereferenceable>::value_type shall -be well formed. [Note: These requirements need not apply to -explicit or partial specializations of pointee] | -
---|
type is determined according to the following algorithm, where -x is an object of type Dereferenceable:
--if ( ++x is ill-formed ) -{ - return ``Dereferenceable::element_type`` -} -else if (``*x`` is a mutable reference to - std::iterator_traits<Dereferenceable>::value_type) -{ - return iterator_traits<Dereferenceable>::value_type -} -else -{ - return iterator_traits<Dereferenceable>::value_type const -} --
-template <class Dereferenceable> -struct indirect_reference -{ - typedef /* see below */ type; -}; --
Requires: | For an object x of type Dereferenceable, *x -is well-formed. If ++x is ill-formed it shall neither be -ambiguous nor shall it violate access control, and -pointee<Dereferenceable>::type& shall be well-formed. -Otherwise iterator_traits<Dereferenceable>::reference shall -be well formed. [Note: These requirements need not apply to -explicit or partial specializations of indirect_reference] | -
---|
type is determined according to the following algorithm, where -x is an object of type Dereferenceable:
--if ( ++x is ill-formed ) - return ``pointee<Dereferenceable>::type&`` -else - std::iterator_traits<Dereferenceable>::reference --
-template < - class Iterator - , class Value = use_default - , class CategoryOrTraversal = use_default - , class Reference = use_default - , class Difference = use_default -> -class indirect_iterator -{ - public: - typedef /* see below */ value_type; - typedef /* see below */ reference; - typedef /* see below */ pointer; - typedef /* see below */ difference_type; - typedef /* see below */ iterator_category; - - indirect_iterator(); - indirect_iterator(Iterator x); - - template < - class Iterator2, class Value2, class Category2 - , class Reference2, class Difference2 - > - indirect_iterator( - indirect_iterator< - Iterator2, Value2, Category2, Reference2, Difference2 - > const& y - , typename enable_if_convertible<Iterator2, Iterator>::type* = 0 // exposition - ); - - Iterator const& base() const; - reference operator*() const; - indirect_iterator& operator++(); - indirect_iterator& operator--(); -private: - Iterator m_iterator; // exposition -}; --
The member types of indirect_iterator are defined according to -the following pseudo-code, where V is -iterator_traits<Iterator>::value_type
--if (Value is use_default) then - typedef remove_const<pointee<V>::type>::type value_type; -else - typedef remove_const<Value>::type value_type; - -if (Reference is use_default) then - if (Value is use_default) then - typedef indirect_reference<V>::type reference; - else - typedef Value& reference; -else - typedef Reference reference; - -if (Value is use_default) then - typedef pointee<V>::type* pointer; -else - typedef Value* pointer; - -if (Difference is use_default) - typedef iterator_traits<Iterator>::difference_type difference_type; -else - typedef Difference difference_type; - -if (CategoryOrTraversal is use_default) - typedef iterator-category ( - iterator_traversal<Iterator>::type,``reference``,``value_type`` - ) iterator_category; -else - typedef iterator-category ( - CategoryOrTraversal,``reference``,``value_type`` - ) iterator_category; --
The expression *v, where v is an object of -iterator_traits<Iterator>::value_type, shall be valid -expression and convertible to reference. Iterator shall -model the traversal concept indicated by iterator_category. -Value, Reference, and Difference shall be chosen so -that value_type, reference, and difference_type meet -the requirements indicated by iterator_category.
-[Note: there are further requirements on the -iterator_traits<Iterator>::value_type if the Value -parameter is not use_default, as implied by the algorithm for -deducing the default for the value_type member.]
-In addition to the concepts indicated by iterator_category -and by iterator_traversal<indirect_iterator>::type, a -specialization of indirect_iterator models the following -concepts, Where v is an object of -iterator_traits<Iterator>::value_type:
----
-- Readable Iterator if reference(*v) is convertible to -value_type.
-- Writable Iterator if reference(*v) = t is a valid -expression (where t is an object of type -indirect_iterator::value_type)
-- Lvalue Iterator if reference is a reference type.
-
indirect_iterator<X,V1,C1,R1,D1> is interoperable with -indirect_iterator<Y,V2,C2,R2,D2> if and only if X is -interoperable with Y.
-In addition to the operations required by the concepts described -above, specializations of indirect_iterator provide the -following operations.
-indirect_iterator();
-Requires: | Iterator must be Default Constructible. | -
---|---|
Effects: | Constructs an instance of indirect_iterator with -a default-constructed m_iterator. | -
indirect_iterator(Iterator x);
-Effects: | Constructs an instance of indirect_iterator with -m_iterator copy constructed from x. | -
---|
-template < - class Iterator2, class Value2, unsigned Access, class Traversal - , class Reference2, class Difference2 -> -indirect_iterator( - indirect_iterator< - Iterator2, Value2, Access, Traversal, Reference2, Difference2 - > const& y - , typename enable_if_convertible<Iterator2, Iterator>::type* = 0 // exposition -); --
Requires: | Iterator2 is implicitly convertible to Iterator. | -
---|---|
Effects: | Constructs an instance of indirect_iterator whose -m_iterator subobject is constructed from y.base(). | -
Iterator const& base() const;
-Returns: | m_iterator | -
---|
reference operator*() const;
-Returns: | **m_iterator | -
---|
indirect_iterator& operator++();
-Effects: | ++m_iterator | -
---|---|
Returns: | *this | -
indirect_iterator& operator--();
-Effects: | --m_iterator | -
---|---|
Returns: | *this | -
The reverse iterator adaptor iterates through the adapted iterator -range in the opposite direction.
--template <class Iterator> -class reverse_iterator -{ -public: - typedef iterator_traits<Iterator>::value_type value_type; - typedef iterator_traits<Iterator>::reference reference; - typedef iterator_traits<Iterator>::pointer pointer; - typedef iterator_traits<Iterator>::difference_type difference_type; - typedef /* see below */ iterator_category; - - reverse_iterator() {} - explicit reverse_iterator(Iterator x) ; - - template<class OtherIterator> - reverse_iterator( - reverse_iterator<OtherIterator> const& r - , typename enable_if_convertible<OtherIterator, Iterator>::type* = 0 // exposition - ); - Iterator const& base() const; - reference operator*() const; - reverse_iterator& operator++(); - reverse_iterator& operator--(); -private: - Iterator m_iterator; // exposition -}; --
If Iterator models Random Access Traversal Iterator and Readable -Lvalue Iterator, then iterator_category is convertible to -random_access_iterator_tag. Otherwise, if -Iterator models Bidirectional Traversal Iterator and Readable -Lvalue Iterator, then iterator_category is convertible to -bidirectional_iterator_tag. Otherwise, iterator_category is -convertible to input_iterator_tag.
-Iterator must be a model of Bidirectional Traversal Iterator. The -type iterator_traits<Iterator>::reference must be the type of -*i, where i is an object of type Iterator.
-A specialization of reverse_iterator models the same iterator -traversal and iterator access concepts modeled by its Iterator -argument. In addition, it may model old iterator concepts -specified in the following table:
-If I models | -then reverse_iterator<I> models | -
---|---|
Readable Lvalue Iterator, -Bidirectional Traversal Iterator | -Bidirectional Iterator | -
Writable Lvalue Iterator, -Bidirectional Traversal Iterator | -Mutable Bidirectional Iterator | -
Readable Lvalue Iterator, -Random Access Traversal Iterator | -Random Access Iterator | -
Writable Lvalue Iterator, -Random Access Traversal Iterator | -Mutable Random Access Iterator | -
reverse_iterator<X> is interoperable with -reverse_iterator<Y> if and only if X is interoperable with -Y.
-In addition to the operations required by the concepts modeled by -reverse_iterator, reverse_iterator provides the following -operations.
-reverse_iterator();
-Requires: | Iterator must be Default Constructible. | -
---|---|
Effects: | Constructs an instance of reverse_iterator with m_iterator -default constructed. | -
explicit reverse_iterator(Iterator x);
-Effects: | Constructs an instance of reverse_iterator with -m_iterator copy constructed from x. | -
---|
-template<class OtherIterator> -reverse_iterator( - reverse_iterator<OtherIterator> const& r - , typename enable_if_convertible<OtherIterator, Iterator>::type* = 0 // exposition -); --
Requires: | OtherIterator is implicitly convertible to Iterator. | -
---|---|
Effects: | Constructs instance of reverse_iterator whose -m_iterator subobject is constructed from y.base(). | -
Iterator const& base() const;
-Returns: | m_iterator | -
---|
reference operator*() const;
-Effects: | - |
---|
-Iterator tmp = m_iterator; -return *--tmp; --
reverse_iterator& operator++();
-Effects: | --m_iterator | -
---|---|
Returns: | *this | -
reverse_iterator& operator--();
-Effects: | ++m_iterator | -
---|---|
Returns: | *this | -
The transform iterator adapts an iterator by modifying the -operator* to apply a function object to the result of -dereferencing the iterator and returning the result.
--template <class UnaryFunction, - class Iterator, - class Reference = use_default, - class Value = use_default> -class transform_iterator -{ -public: - typedef /* see below */ value_type; - typedef /* see below */ reference; - typedef /* see below */ pointer; - typedef iterator_traits<Iterator>::difference_type difference_type; - typedef /* see below */ iterator_category; - - transform_iterator(); - transform_iterator(Iterator const& x, UnaryFunction f); - - template<class F2, class I2, class R2, class V2> - transform_iterator( - transform_iterator<F2, I2, R2, V2> const& t - , typename enable_if_convertible<I2, Iterator>::type* = 0 // exposition only - , typename enable_if_convertible<F2, UnaryFunction>::type* = 0 // exposition only - ); - UnaryFunction functor() const; - Iterator const& base() const; - reference operator*() const; - transform_iterator& operator++(); - transform_iterator& operator--(); -private: - Iterator m_iterator; // exposition only - UnaryFunction m_f; // exposition only -}; --
If Reference is use_default then the reference member of -transform_iterator is -result_of<UnaryFunction(iterator_traits<Iterator>::reference)>::type. -Otherwise, reference is Reference.
-If Value is use_default then the value_type member is -remove_cv<remove_reference<reference> >::type. Otherwise, -value_type is Value.
-If Iterator models Readable Lvalue Iterator and if Iterator -models Random Access Traversal Iterator, then iterator_category is -convertible to random_access_iterator_tag. Otherwise, if -Iterator models Bidirectional Traversal Iterator, then -iterator_category is convertible to -bidirectional_iterator_tag. Otherwise iterator_category is -convertible to forward_iterator_tag. If Iterator does not -model Readable Lvalue Iterator then iterator_category is -convertible to input_iterator_tag.
-The type UnaryFunction must be Assignable, Copy Constructible, and -the expression f(*i) must be valid where f is an object of -type UnaryFunction, i is an object of type Iterator, and -where the type of f(*i) must be -result_of<UnaryFunction(iterator_traits<Iterator>::reference)>::type.
-The argument Iterator shall model Readable Iterator.
-The resulting transform_iterator models the most refined of the -following that is also modeled by Iterator.
----
-- Writable Lvalue Iterator if transform_iterator::reference is a non-const reference.
-- Readable Lvalue Iterator if transform_iterator::reference is a const reference.
-- Readable Iterator otherwise.
-
The transform_iterator models the most refined standard traversal -concept that is modeled by the Iterator argument.
-If transform_iterator is a model of Readable Lvalue Iterator then -it models the following original iterator concepts depending on what -the Iterator argument models.
-If Iterator models | -then transform_iterator models | -
---|---|
Single Pass Iterator | -Input Iterator | -
Forward Traversal Iterator | -Forward Iterator | -
Bidirectional Traversal Iterator | -Bidirectional Iterator | -
Random Access Traversal Iterator | -Random Access Iterator | -
If transform_iterator models Writable Lvalue Iterator then it is a -mutable iterator (as defined in the old iterator requirements).
-transform_iterator<F1, X, R1, V1> is interoperable with -transform_iterator<F2, Y, R2, V2> if and only if X is -interoperable with Y.
-In addition to the operations required by the concepts modeled by -transform_iterator, transform_iterator provides the following -operations.
-transform_iterator();
-Returns: | An instance of transform_iterator with m_f -and m_iterator default constructed. | -
---|
transform_iterator(Iterator const& x, UnaryFunction f);
-Returns: | An instance of transform_iterator with m_f -initialized to f and m_iterator initialized to x. | -
---|
-template<class F2, class I2, class R2, class V2> -transform_iterator( - transform_iterator<F2, I2, R2, V2> const& t - , typename enable_if_convertible<I2, Iterator>::type* = 0 // exposition only - , typename enable_if_convertible<F2, UnaryFunction>::type* = 0 // exposition only -); --
Returns: | An instance of transform_iterator with m_f -initialized to t.functor() and m_iterator initialized to -t.base(). | -
---|---|
Requires: | OtherIterator is implicitly convertible to Iterator. | -
UnaryFunction functor() const;
-Returns: | m_f | -
---|
Iterator const& base() const;
-Returns: | m_iterator | -
---|
reference operator*() const;
-Returns: | m_f(*m_iterator) | -
---|
transform_iterator& operator++();
-Effects: | ++m_iterator | -
---|---|
Returns: | *this | -
transform_iterator& operator--();
-Effects: | --m_iterator | -
---|---|
Returns: | *this | -
The filter iterator adaptor creates a view of an iterator range in -which some elements of the range are skipped. A predicate function -object controls which elements are skipped. When the predicate is -applied to an element, if it returns true then the element is -retained and if it returns false then the element is skipped -over. When skipping over elements, it is necessary for the filter -adaptor to know when to stop so as to avoid going past the end of the -underlying range. A filter iterator is therefore constructed with pair -of iterators indicating the range of elements in the unfiltered -sequence to be traversed.
--template <class Predicate, class Iterator> -class filter_iterator -{ - public: - typedef iterator_traits<Iterator>::value_type value_type; - typedef iterator_traits<Iterator>::reference reference; - typedef iterator_traits<Iterator>::pointer pointer; - typedef iterator_traits<Iterator>::difference_type difference_type; - typedef /* see below */ iterator_category; - - filter_iterator(); - filter_iterator(Predicate f, Iterator x, Iterator end = Iterator()); - filter_iterator(Iterator x, Iterator end = Iterator()); - template<class OtherIterator> - filter_iterator( - filter_iterator<Predicate, OtherIterator> const& t - , typename enable_if_convertible<OtherIterator, Iterator>::type* = 0 // exposition - ); - Predicate predicate() const; - Iterator end() const; - Iterator const& base() const; - reference operator*() const; - filter_iterator& operator++(); -private: - Predicate m_pred; // exposition only - Iterator m_iter; // exposition only - Iterator m_end; // exposition only -}; --
If Iterator models Readable Lvalue Iterator and Bidirectional Traversal -Iterator then iterator_category is convertible to -std::bidirectional_iterator_tag. -Otherwise, if Iterator models Readable Lvalue Iterator and Forward Traversal -Iterator then iterator_category is convertible to -std::forward_iterator_tag. -Otherwise iterator_category is -convertible to std::input_iterator_tag.
-The Iterator argument shall meet the requirements of Readable -Iterator and Single Pass Iterator or it shall meet the requirements of -Input Iterator.
-The Predicate argument must be Assignable, Copy Constructible, and -the expression p(x) must be valid where p is an object of type -Predicate, x is an object of type -iterator_traits<Iterator>::value_type, and where the type of -p(x) must be convertible to bool.
-The concepts that filter_iterator models are dependent on which -concepts the Iterator argument models, as specified in the -following tables.
-If Iterator models | -then filter_iterator models | -
---|---|
Single Pass Iterator | -Single Pass Iterator | -
Forward Traversal Iterator | -Forward Traversal Iterator | -
Bidirectional Traversal Iterator | -Bidirectional Traversal Iterator | -
If Iterator models | -then filter_iterator models | -
---|---|
Readable Iterator | -Readable Iterator | -
Writable Iterator | -Writable Iterator | -
Lvalue Iterator | -Lvalue Iterator | -
If Iterator models | -then filter_iterator models | -
---|---|
Readable Iterator, Single Pass Iterator | -Input Iterator | -
Readable Lvalue Iterator, Forward Traversal Iterator | -Forward Iterator | -
Writable Lvalue Iterator, Forward Traversal Iterator | -Mutable Forward Iterator | -
Writable Lvalue Iterator, Bidirectional Iterator | -Mutable Bidirectional Iterator | -
filter_iterator<P1, X> is interoperable with filter_iterator<P2, Y> -if and only if X is interoperable with Y.
-In addition to those operations required by the concepts that -filter_iterator models, filter_iterator provides the following -operations.
-filter_iterator();
-Requires: | Predicate and Iterator must be Default Constructible. | -
---|---|
Effects: | Constructs a filter_iterator whose``m_pred``, m_iter, and m_end -members are a default constructed. | -
filter_iterator(Predicate f, Iterator x, Iterator end = Iterator());
-Effects: | Constructs a filter_iterator where m_iter is either -the first position in the range [x,end) such that f(*m_iter) == true -or else``m_iter == end``. The member m_pred is constructed from -f and m_end from end. | -
---|
filter_iterator(Iterator x, Iterator end = Iterator());
-Requires: | Predicate must be Default Constructible and -Predicate is a class type (not a function pointer). | -
---|---|
Effects: | Constructs a filter_iterator where m_iter is either -the first position in the range [x,end) such that m_pred(*m_iter) == true -or else``m_iter == end``. The member m_pred is default constructed. | -
-template <class OtherIterator> -filter_iterator( - filter_iterator<Predicate, OtherIterator> const& t - , typename enable_if_convertible<OtherIterator, Iterator>::type* = 0 // exposition - );`` --
Requires: | OtherIterator is implicitly convertible to Iterator. | -
---|---|
Effects: | Constructs a filter iterator whose members are copied from t. | -
Predicate predicate() const;
-Returns: | m_pred | -
---|
Iterator end() const;
-Returns: | m_end | -
---|
Iterator const& base() const;
-Returns: | m_iterator | -
---|
reference operator*() const;
-Returns: | *m_iter | -
---|
filter_iterator& operator++();
-Effects: | Increments m_iter and then continues to -increment m_iter until either m_iter == m_end -or m_pred(*m_iter) == true. | -
---|---|
Returns: | *this | -
counting_iterator adapts an object by adding an operator* that -returns the current value of the object. All other iterator operations -are forwarded to the adapted object.
--template < - class Incrementable - , class CategoryOrTraversal = use_default - , class Difference = use_default -> -class counting_iterator -{ -public: - typedef Incrementable value_type; - typedef const Incrementable& reference; - typedef const Incrementable* pointer; - typedef /* see below */ difference_type; - typedef /* see below */ iterator_category; - - counting_iterator(); - counting_iterator(counting_iterator const& rhs); - explicit counting_iterator(Incrementable x); - Incrementable const& base() const; - reference operator*() const; - counting_iterator& operator++(); - counting_iterator& operator--(); -private: - Incrementable m_inc; // exposition -}; --
If the Difference argument is use_default then -difference_type is an unspecified signed integral -type. Otherwise difference_type is Difference.
-iterator_category is determined according to the following -algorithm:
--if (CategoryOrTraversal is not use_default) - return CategoryOrTraversal -else if (numeric_limits<Incrementable>::is_specialized) - return iterator-category( - random_access_traversal_tag, Incrementable, const Incrementable&) -else - return iterator-category( - iterator_traversal<Incrementable>::type, - Incrementable, const Incrementable&) --
The Incrementable argument shall be Copy Constructible and Assignable.
-If iterator_category is convertible to forward_iterator_tag -or forward_traversal_tag, the following must be well-formed:
--Incrementable i, j; -++i; // pre-increment -i == j; // operator equal --
If iterator_category is convertible to -bidirectional_iterator_tag or bidirectional_traversal_tag, -the following expression must also be well-formed:
----i --
If iterator_category is convertible to -random_access_iterator_tag or random_access_traversal_tag, -the following must must also be valid:
--counting_iterator::difference_type n; -i += n; -n = i - j; -i < j; --
Specializations of counting_iterator model Readable Lvalue -Iterator. In addition, they model the concepts corresponding to the -iterator tags to which their iterator_category is convertible. -Also, if CategoryOrTraversal is not use_default then -counting_iterator models the concept corresponding to the iterator -tag CategoryOrTraversal. Otherwise, if -numeric_limits<Incrementable>::is_specialized, then -counting_iterator models Random Access Traversal Iterator. -Otherwise, counting_iterator models the same iterator traversal -concepts modeled by Incrementable.
-counting_iterator<X,C1,D1> is interoperable with -counting_iterator<Y,C2,D2> if and only if X is -interoperable with Y.
-In addition to the operations required by the concepts modeled by -counting_iterator, counting_iterator provides the following -operations.
-counting_iterator();
-Requires: | Incrementable is Default Constructible. | -
---|---|
Effects: | Default construct the member m_inc. | -
counting_iterator(counting_iterator const& rhs);
-Effects: | Construct member m_inc from rhs.m_inc. | -
---|
explicit counting_iterator(Incrementable x);
-Effects: | Construct member m_inc from x. | -
---|
reference operator*() const;
-Returns: | m_inc | -
---|
counting_iterator& operator++();
-Effects: | ++m_inc | -
---|---|
Returns: | *this | -
counting_iterator& operator--();
-Effects: | --m_inc | -
---|---|
Returns: | *this | -
Incrementable const& base() const;
-Returns: | m_inc | -
---|
The function output iterator adaptor makes it easier to create custom -output iterators. The adaptor takes a unary function and creates a -model of Output Iterator. Each item assigned to the output iterator is -passed as an argument to the unary function. The motivation for this -iterator is that creating a conforming output iterator is non-trivial, -particularly because the proper implementation usually requires a -proxy object.
- --#include <boost/function_output_iterator.hpp> --
-template <class UnaryFunction> -class function_output_iterator { -public: - typedef std::output_iterator_tag iterator_category; - typedef void value_type; - typedef void difference_type; - typedef void pointer; - typedef void reference; - - explicit function_output_iterator(); - - explicit function_output_iterator(const UnaryFunction& f); - - /* see below */ operator*(); - function_output_iterator& operator++(); - function_output_iterator& operator++(int); -private: - UnaryFunction m_f; // exposition only -}; --
UnaryFunction must be Assignable and Copy Constructible.
-function_output_iterator is a model of the Writable and -Incrementable Iterator concepts.
-explicit function_output_iterator(const UnaryFunction& f = UnaryFunction());
-Effects: | Constructs an instance of function_output_iterator -with m_f constructed from f. | -
---|
operator*();
-Returns: | An object r of unspecified type such that r = t -is equivalent to m_f(t) for all t. | -
---|
function_output_iterator& operator++();
-Returns: | *this | -
---|
function_output_iterator& operator++(int);
-Returns: | *this | -
---|
Author: | -David Abrahams, Jeremy Siek, Thomas Witt |
---|---|
Contact: | -dave@boost-consulting.com, jsiek@osl.iu.edu, witt@ive.uni-hannover.de |
Organization: | -Boost Consulting, Indiana University Open Systems -Lab, University of Hanover Institute for Transport -Railway Operation and Construction |
Date: | -2004-11-01 |
Copyright: | -Copyright David Abrahams, Jeremy Siek, and Thomas Witt 2003. |
abstract: | - - -The filter iterator adaptor creates a view of an iterator range in -which some elements of the range are skipped. A predicate function -object controls which elements are skipped. When the predicate is -applied to an element, if it returns true then the element is -retained and if it returns false then the element is skipped -over. When skipping over elements, it is necessary for the filter -adaptor to know when to stop so as to avoid going past the end of the -underlying range. A filter iterator is therefore constructed with pair -of iterators indicating the range of elements in the unfiltered -sequence to be traversed. | -
---|
-template <class Predicate, class Iterator> -class filter_iterator -{ - public: - typedef iterator_traits<Iterator>::value_type value_type; - typedef iterator_traits<Iterator>::reference reference; - typedef iterator_traits<Iterator>::pointer pointer; - typedef iterator_traits<Iterator>::difference_type difference_type; - typedef /* see below */ iterator_category; - - filter_iterator(); - filter_iterator(Predicate f, Iterator x, Iterator end = Iterator()); - filter_iterator(Iterator x, Iterator end = Iterator()); - template<class OtherIterator> - filter_iterator( - filter_iterator<Predicate, OtherIterator> const& t - , typename enable_if_convertible<OtherIterator, Iterator>::type* = 0 // exposition - ); - Predicate predicate() const; - Iterator end() const; - Iterator const& base() const; - reference operator*() const; - filter_iterator& operator++(); -private: - Predicate m_pred; // exposition only - Iterator m_iter; // exposition only - Iterator m_end; // exposition only -}; --
If Iterator models Readable Lvalue Iterator and Bidirectional Traversal -Iterator then iterator_category is convertible to -std::bidirectional_iterator_tag. -Otherwise, if Iterator models Readable Lvalue Iterator and Forward Traversal -Iterator then iterator_category is convertible to -std::forward_iterator_tag. -Otherwise iterator_category is -convertible to std::input_iterator_tag.
-The Iterator argument shall meet the requirements of Readable -Iterator and Single Pass Iterator or it shall meet the requirements of -Input Iterator.
-The Predicate argument must be Assignable, Copy Constructible, and -the expression p(x) must be valid where p is an object of type -Predicate, x is an object of type -iterator_traits<Iterator>::value_type, and where the type of -p(x) must be convertible to bool.
-The concepts that filter_iterator models are dependent on which -concepts the Iterator argument models, as specified in the -following tables.
-If Iterator models | -then filter_iterator models | -
---|---|
Single Pass Iterator | -Single Pass Iterator | -
Forward Traversal Iterator | -Forward Traversal Iterator | -
Bidirectional Traversal Iterator | -Bidirectional Traversal Iterator | -
If Iterator models | -then filter_iterator models | -
---|---|
Readable Iterator | -Readable Iterator | -
Writable Iterator | -Writable Iterator | -
Lvalue Iterator | -Lvalue Iterator | -
If Iterator models | -then filter_iterator models | -
---|---|
Readable Iterator, Single Pass Iterator | -Input Iterator | -
Readable Lvalue Iterator, Forward Traversal Iterator | -Forward Iterator | -
Writable Lvalue Iterator, Forward Traversal Iterator | -Mutable Forward Iterator | -
Writable Lvalue Iterator, Bidirectional Iterator | -Mutable Bidirectional Iterator | -
filter_iterator<P1, X> is interoperable with filter_iterator<P2, Y> -if and only if X is interoperable with Y.
-In addition to those operations required by the concepts that -filter_iterator models, filter_iterator provides the following -operations.
-filter_iterator();
-Requires: | Predicate and Iterator must be Default Constructible. | -
---|---|
Effects: | Constructs a filter_iterator whose``m_pred``, m_iter, and m_end -members are a default constructed. | -
filter_iterator(Predicate f, Iterator x, Iterator end = Iterator());
-Effects: | Constructs a filter_iterator where m_iter is either -the first position in the range [x,end) such that f(*m_iter) == true -or else``m_iter == end``. The member m_pred is constructed from -f and m_end from end. | -
---|
filter_iterator(Iterator x, Iterator end = Iterator());
-Requires: | Predicate must be Default Constructible and -Predicate is a class type (not a function pointer). | -
---|---|
Effects: | Constructs a filter_iterator where m_iter is either -the first position in the range [x,end) such that m_pred(*m_iter) == true -or else``m_iter == end``. The member m_pred is default constructed. | -
-template <class OtherIterator> -filter_iterator( - filter_iterator<Predicate, OtherIterator> const& t - , typename enable_if_convertible<OtherIterator, Iterator>::type* = 0 // exposition - );`` --
Requires: | OtherIterator is implicitly convertible to Iterator. | -
---|---|
Effects: | Constructs a filter iterator whose members are copied from t. | -
Predicate predicate() const;
-Returns: | m_pred | -
---|
Iterator end() const;
-Returns: | m_end | -
---|
Iterator const& base() const;
-Returns: | m_iterator | -
---|
reference operator*() const;
-Returns: | *m_iter | -
---|
filter_iterator& operator++();
-Effects: | Increments m_iter and then continues to -increment m_iter until either m_iter == m_end -or m_pred(*m_iter) == true. | -
---|---|
Returns: | *this | -
-template <class Predicate, class Iterator> -filter_iterator<Predicate,Iterator> -make_filter_iterator(Predicate f, Iterator x, Iterator end = Iterator()); --
Returns: | filter_iterator<Predicate,Iterator>(f, x, end) | -
---|
-template <class Predicate, class Iterator> -filter_iterator<Predicate,Iterator> -make_filter_iterator(Iterator x, Iterator end = Iterator()); --
Returns: | filter_iterator<Predicate,Iterator>(x, end) | -
---|
This example uses filter_iterator and then -make_filter_iterator to output only the positive integers from an -array of integers. Then make_filter_iterator is is used to output -the integers greater than -2.
--struct is_positive_number { - bool operator()(int x) { return 0 < x; } -}; - -int main() -{ - int numbers_[] = { 0, -1, 4, -3, 5, 8, -2 }; - const int N = sizeof(numbers_)/sizeof(int); - - typedef int* base_iterator; - base_iterator numbers(numbers_); - - // Example using filter_iterator - typedef boost::filter_iterator<is_positive_number, base_iterator> - FilterIter; - - is_positive_number predicate; - FilterIter filter_iter_first(predicate, numbers, numbers + N); - FilterIter filter_iter_last(predicate, numbers + N, numbers + N); - - std::copy(filter_iter_first, filter_iter_last, std::ostream_iterator<int>(std::cout, " ")); - std::cout << std::endl; - - // Example using make_filter_iterator() - std::copy(boost::make_filter_iterator<is_positive_number>(numbers, numbers + N), - boost::make_filter_iterator<is_positive_number>(numbers + N, numbers + N), - std::ostream_iterator<int>(std::cout, " ")); - std::cout << std::endl; - - // Another example using make_filter_iterator() - std::copy( - boost::make_filter_iterator( - std::bind2nd(std::greater<int>(), -2) - , numbers, numbers + N) - - , boost::make_filter_iterator( - std::bind2nd(std::greater<int>(), -2) - , numbers + N, numbers + N) - - , std::ostream_iterator<int>(std::cout, " ") - ); - - std::cout << std::endl; - - return boost::exit_success; -} --
The output is:
--4 5 8 -4 5 8 -0 -1 4 5 8 --
The source code for this example can be found here.
-Author: | -David Abrahams, Jeremy Siek, Thomas Witt |
---|---|
Contact: | -dave@boost-consulting.com, jsiek@osl.iu.edu, witt@ive.uni-hannover.de |
Organization: | -Boost Consulting, Indiana University Open Systems -Lab, University of Hanover Institute for Transport -Railway Operation and Construction |
Date: | -2004-11-01 |
Copyright: | -Copyright David Abrahams, Jeremy Siek, and Thomas Witt 2003. |
abstract: | - - -The function output iterator adaptor makes it easier to create custom -output iterators. The adaptor takes a unary function and creates a -model of Output Iterator. Each item assigned to the output iterator is -passed as an argument to the unary function. The motivation for this -iterator is that creating a conforming output iterator is non-trivial, -particularly because the proper implementation usually requires a -proxy object. | -
---|
-#include <boost/function_output_iterator.hpp> --
-template <class UnaryFunction> -class function_output_iterator { -public: - typedef std::output_iterator_tag iterator_category; - typedef void value_type; - typedef void difference_type; - typedef void pointer; - typedef void reference; - - explicit function_output_iterator(); - - explicit function_output_iterator(const UnaryFunction& f); - - /* see below */ operator*(); - function_output_iterator& operator++(); - function_output_iterator& operator++(int); -private: - UnaryFunction m_f; // exposition only -}; --
UnaryFunction must be Assignable and Copy Constructible.
-function_output_iterator is a model of the Writable and -Incrementable Iterator concepts.
-explicit function_output_iterator(const UnaryFunction& f = UnaryFunction());
-Effects: | Constructs an instance of function_output_iterator -with m_f constructed from f. | -
---|
operator*();
-Returns: | An object r of unspecified type such that r = t -is equivalent to m_f(t) for all t. | -
---|
function_output_iterator& operator++();
-Returns: | *this | -
---|
function_output_iterator& operator++(int);
-Returns: | *this | -
---|
-struct string_appender -{ - string_appender(std::string& s) - : m_str(&s) - {} - - void operator()(const std::string& x) const - { - *m_str += x; - } - - std::string* m_str; -}; - -int main(int, char*[]) -{ - std::vector<std::string> x; - x.push_back("hello"); - x.push_back(" "); - x.push_back("world"); - x.push_back("!"); - - std::string s = ""; - std::copy(x.begin(), x.end(), - boost::make_function_output_iterator(string_appender(s))); - - std::cout << s << std::endl; - - return 0; -} --
Authors: | David Abrahams, Jeremy Siek, Thomas Witt | -
---|---|
Contact: | dave@boost-consulting.com, jsiek@osl.iu.edu, witt@styleadvisor.com | -
organizations: | Boost Consulting, Indiana University Open Systems -Lab, Zephyr Associates, Inc. | -
date: | $Date$ | -
copyright: | Copyright David Abrahams, Jeremy Siek, Thomas Witt 2003. | -
Abstract: | The Boost Iterator Library contains two parts. The first -is a system of concepts which extend the C++ standard -iterator requirements. The second is a framework of -components for building iterators based on these -extended concepts and includes several useful iterator -adaptors. The extended iterator concepts have been -carefully designed so that old-style iterators -can fit in the new concepts and so that new-style -iterators will be compatible with old-style algorithms, -though algorithms may need to be updated if they want to -take full advantage of the new-style iterator -capabilities. Several components of this library have -been accepted into the C++ standard technical report. -The components of the Boost Iterator Library replace the -older Boost Iterator Adaptor Library. | -
---|
The iterator categories defined in C++98 are extremely limiting -because they bind together two orthogonal concepts: traversal and -element access. For example, because a random access iterator is -required to return a reference (and not a proxy) when dereferenced, -it is impossible to capture the capabilities of -vector<bool>::iterator using the C++98 categories. This is the -infamous "vector<bool> is not a container, and its iterators -aren't random access iterators", debacle about which Herb Sutter -wrote two papers for the standards comittee (n1185 and n1211), -and a Guru of the Week. New-style iterators go well beyond -patching up vector<bool>, though: there are lots of other -iterators already in use which can't be adequately represented by -the existing concepts. For details about the new iterator -concepts, see our
--Standard Proposal For New-Style Iterators (PDF)-
Writing standard-conforming iterators is tricky, but the need comes -up often. In order to ease the implementation of new iterators, -the Boost.Iterator library provides the iterator_facade class template, -which implements many useful defaults and compile-time checks -designed to help the iterator author ensure that his iterator is -correct.
-It is also common to define a new iterator that is similar to some -underlying iterator or iterator-like type, but that modifies some -aspect of the underlying type's behavior. For that purpose, the -library supplies the iterator_adaptor class template, which is specially -designed to take advantage of as much of the underlying type's -behavior as possible.
-The documentation for these two classes can be found at the following -web pages:
-Both iterator_facade and iterator_adaptor as well as many of the specialized -adaptors mentioned below have been proposed for standardization, -and accepted into the first C++ technical report; see our
--Standard Proposal For Iterator Facade and Adaptor (PDF)-
for more details.
-The iterator library supplies a useful suite of standard-conforming -iterator templates based on the Boost iterator facade and adaptor.
-If you have been using the old Boost Iterator Adaptor library to -implement iterators, you probably wrote a Policies class which -captures the core operations of your iterator. In the new library -design, you'll move those same core operations into the body of the -iterator class itself. If you were writing a family of iterators, -you probably wrote a type generator to build the -iterator_adaptor specialization you needed; in the new library -design you don't need a type generator (though may want to keep it -around as a compatibility aid for older code) because, due to the -use of the Curiously Recurring Template Pattern (CRTP) [Cop95], -you can now define the iterator class yourself and acquire -functionality through inheritance from iterator_facade or -iterator_adaptor. As a result, you also get much finer control -over how your iterator works: you can add additional constructors, -or even override the iterator functionality provided by the -library.
-If you're looking for the old projection_iterator component, -its functionality has been merged into transform_iterator: as -long as the function object's result_type (or the Reference -template argument, if explicitly specified) is a true reference -type, transform_iterator will behave like -projection_iterator used to.
-In 2000 Dave Abrahams was writing an iterator for a container of -pointers, which would access the pointed-to elements when -dereferenced. Naturally, being a library writer, he decided to -generalize the idea and the Boost Iterator Adaptor library was born. -Dave was inspired by some writings of Andrei Alexandrescu and chose a -policy based design (though he probably didn't capture Andrei's idea -very well - there was only one policy class for all the iterator's -orthogonal properties). Soon Jeremy Siek realized he would need the -library and they worked together to produce a "Boostified" version, -which was reviewed and accepted into the library. They wrote a paper -and made several important revisions of the code.
-Eventually, several shortcomings of the older library began to make -the need for a rewrite apparent. Dave and Jeremy started working -at the Santa Cruz C++ committee meeting in 2002, and had quickly -generated a working prototype. At the urging of Mat Marcus, they -decided to use the GenVoca/CRTP pattern approach, and moved the -policies into the iterator class itself. Thomas Witt expressed -interest and became the voice of strict compile-time checking for -the project, adding uses of the SFINAE technique to eliminate false -converting constructors and operators from the overload set. He -also recognized the need for a separate iterator_facade, and -factored it out of iterator_adaptor. Finally, after a -near-complete rewrite of the prototype, they came up with the -library you see today.
-[Cop95] | [Coplien, 1995] Coplien, J., Curiously Recurring Template -Patterns, C++ Report, February 1995, pp. 24-27. |
Author: | -David Abrahams, Jeremy Siek, Thomas Witt |
---|---|
Contact: | -dave@boost-consulting.com, jsiek@osl.iu.edu, witt@ive.uni-hannover.de |
Organization: | -Boost Consulting, Indiana University Open Systems -Lab, University of Hanover Institute for Transport -Railway Operation and Construction |
Date: | -2004-11-01 |
Copyright: | -Copyright David Abrahams, Jeremy Siek, and Thomas Witt 2003. |
abstract: | - - -indirect_iterator adapts an iterator by applying an -extra dereference inside of operator*(). For example, this -iterator adaptor makes it possible to view a container of pointers -(e.g. list<foo*>) as if it were a container of the pointed-to type -(e.g. list<foo>). indirect_iterator depends on two -auxiliary traits, pointee and indirect_reference, to -provide support for underlying iterators whose value_type is -not an iterator. | -
---|
-template < - class Iterator - , class Value = use_default - , class CategoryOrTraversal = use_default - , class Reference = use_default - , class Difference = use_default -> -class indirect_iterator -{ - public: - typedef /* see below */ value_type; - typedef /* see below */ reference; - typedef /* see below */ pointer; - typedef /* see below */ difference_type; - typedef /* see below */ iterator_category; - - indirect_iterator(); - indirect_iterator(Iterator x); - - template < - class Iterator2, class Value2, class Category2 - , class Reference2, class Difference2 - > - indirect_iterator( - indirect_iterator< - Iterator2, Value2, Category2, Reference2, Difference2 - > const& y - , typename enable_if_convertible<Iterator2, Iterator>::type* = 0 // exposition - ); - - Iterator const& base() const; - reference operator*() const; - indirect_iterator& operator++(); - indirect_iterator& operator--(); -private: - Iterator m_iterator; // exposition -}; --
The member types of indirect_iterator are defined according to -the following pseudo-code, where V is -iterator_traits<Iterator>::value_type
--if (Value is use_default) then - typedef remove_const<pointee<V>::type>::type value_type; -else - typedef remove_const<Value>::type value_type; - -if (Reference is use_default) then - if (Value is use_default) then - typedef indirect_reference<V>::type reference; - else - typedef Value& reference; -else - typedef Reference reference; - -if (Value is use_default) then - typedef pointee<V>::type* pointer; -else - typedef Value* pointer; - -if (Difference is use_default) - typedef iterator_traits<Iterator>::difference_type difference_type; -else - typedef Difference difference_type; - -if (CategoryOrTraversal is use_default) - typedef iterator-category ( - iterator_traversal<Iterator>::type,``reference``,``value_type`` - ) iterator_category; -else - typedef iterator-category ( - CategoryOrTraversal,``reference``,``value_type`` - ) iterator_category; --
The expression *v, where v is an object of -iterator_traits<Iterator>::value_type, shall be valid -expression and convertible to reference. Iterator shall -model the traversal concept indicated by iterator_category. -Value, Reference, and Difference shall be chosen so -that value_type, reference, and difference_type meet -the requirements indicated by iterator_category.
-[Note: there are further requirements on the -iterator_traits<Iterator>::value_type if the Value -parameter is not use_default, as implied by the algorithm for -deducing the default for the value_type member.]
-In addition to the concepts indicated by iterator_category -and by iterator_traversal<indirect_iterator>::type, a -specialization of indirect_iterator models the following -concepts, Where v is an object of -iterator_traits<Iterator>::value_type:
----
-- Readable Iterator if reference(*v) is convertible to -value_type.
-- Writable Iterator if reference(*v) = t is a valid -expression (where t is an object of type -indirect_iterator::value_type)
-- Lvalue Iterator if reference is a reference type.
-
indirect_iterator<X,V1,C1,R1,D1> is interoperable with -indirect_iterator<Y,V2,C2,R2,D2> if and only if X is -interoperable with Y.
-In addition to the operations required by the concepts described -above, specializations of indirect_iterator provide the -following operations.
-indirect_iterator();
-Requires: | Iterator must be Default Constructible. | -
---|---|
Effects: | Constructs an instance of indirect_iterator with -a default-constructed m_iterator. | -
indirect_iterator(Iterator x);
-Effects: | Constructs an instance of indirect_iterator with -m_iterator copy constructed from x. | -
---|
-template < - class Iterator2, class Value2, unsigned Access, class Traversal - , class Reference2, class Difference2 -> -indirect_iterator( - indirect_iterator< - Iterator2, Value2, Access, Traversal, Reference2, Difference2 - > const& y - , typename enable_if_convertible<Iterator2, Iterator>::type* = 0 // exposition -); --
Requires: | Iterator2 is implicitly convertible to Iterator. | -
---|---|
Effects: | Constructs an instance of indirect_iterator whose -m_iterator subobject is constructed from y.base(). | -
Iterator const& base() const;
-Returns: | m_iterator | -
---|
reference operator*() const;
-Returns: | **m_iterator | -
---|
indirect_iterator& operator++();
-Effects: | ++m_iterator | -
---|---|
Returns: | *this | -
indirect_iterator& operator--();
-Effects: | --m_iterator | -
---|---|
Returns: | *this | -
This example prints an array of characters, using -indirect_iterator to access the array of characters through an -array of pointers. Next indirect_iterator is used with the -transform algorithm to copy the characters (incremented by one) to -another array. A constant indirect iterator is used for the source and -a mutable indirect iterator is used for the destination. The last part -of the example prints the original array of characters, but this time -using the make_indirect_iterator helper function.
--char characters[] = "abcdefg"; -const int N = sizeof(characters)/sizeof(char) - 1; // -1 since characters has a null char -char* pointers_to_chars[N]; // at the end. -for (int i = 0; i < N; ++i) - pointers_to_chars[i] = &characters[i]; - -// Example of using indirect_iterator - -boost::indirect_iterator<char**, char> - indirect_first(pointers_to_chars), indirect_last(pointers_to_chars + N); - -std::copy(indirect_first, indirect_last, std::ostream_iterator<char>(std::cout, ",")); -std::cout << std::endl; - - -// Example of making mutable and constant indirect iterators - -char mutable_characters[N]; -char* pointers_to_mutable_chars[N]; -for (int j = 0; j < N; ++j) - pointers_to_mutable_chars[j] = &mutable_characters[j]; - -boost::indirect_iterator<char* const*> mutable_indirect_first(pointers_to_mutable_chars), - mutable_indirect_last(pointers_to_mutable_chars + N); -boost::indirect_iterator<char* const*, char const> const_indirect_first(pointers_to_chars), - const_indirect_last(pointers_to_chars + N); - -std::transform(const_indirect_first, const_indirect_last, - mutable_indirect_first, std::bind1st(std::plus<char>(), 1)); - -std::copy(mutable_indirect_first, mutable_indirect_last, - std::ostream_iterator<char>(std::cout, ",")); -std::cout << std::endl; - - -// Example of using make_indirect_iterator() - -std::copy(boost::make_indirect_iterator(pointers_to_chars), - boost::make_indirect_iterator(pointers_to_chars + N), - std::ostream_iterator<char>(std::cout, ",")); -std::cout << std::endl; --
The output is:
--a,b,c,d,e,f,g, -b,c,d,e,f,g,h, -a,b,c,d,e,f,g, --
The source code for this example can be found here.
-Author: | -David Abrahams, Jeremy Siek, Thomas Witt |
---|---|
Contact: | -dave@boost-consulting.com, jsiek@osl.iu.edu, witt@ive.uni-hannover.de |
Organization: | -Boost Consulting, Indiana University Open Systems -Lab, University of Hanover Institute for Transport -Railway Operation and Construction |
Date: | -2004-11-01 |
Copyright: | -Copyright David Abrahams, Jeremy Siek, and Thomas Witt 2003. |
abstract: | - |
---|
Each specialization of the iterator_adaptor class template is derived from -a specialization of iterator_facade. The core interface functions -expected by iterator_facade are implemented in terms of the -iterator_adaptor's Base template parameter. A class derived -from iterator_adaptor typically redefines some of the core -interface functions to adapt the behavior of the Base type. -Whether the derived class models any of the standard iterator concepts -depends on the operations supported by the Base type and which -core interface functions of iterator_facade are redefined in the -Derived class.
-The iterator_adaptor class template adapts some Base [1] -type to create a new iterator. Instantiations of iterator_adaptor -are derived from a corresponding instantiation of iterator_facade -and implement the core behaviors in terms of the Base type. In -essence, iterator_adaptor merely forwards all operations to an -instance of the Base type, which it stores as a member.
-[1] | (1, 2) The term "Base" here does not refer to a base class and is -not meant to imply the use of derivation. We have followed the lead -of the standard library, which provides a base() function to access -the underlying iterator object of a reverse_iterator adaptor. |
The user of iterator_adaptor creates a class derived from an -instantiation of iterator_adaptor and then selectively -redefines some of the core member functions described in the -iterator_facade core requirements table. The Base type need -not meet the full requirements for an iterator; it need only -support the operations used by the core interface functions of -iterator_adaptor that have not been redefined in the user's -derived class.
-Several of the template parameters of iterator_adaptor default -to use_default. This allows the -user to make use of a default parameter even when she wants to -specify a parameter later in the parameter list. Also, the -defaults for the corresponding associated types are somewhat -complicated, so metaprogramming is required to compute them, and -use_default can help to simplify the implementation. Finally, -the identity of the use_default type is not left unspecified -because specification helps to highlight that the Reference -template parameter may not always be identical to the iterator's -reference type, and will keep users from making mistakes based on -that assumption.
--template < - class Derived - , class Base - , class Value = use_default - , class CategoryOrTraversal = use_default - , class Reference = use_default - , class Difference = use_default -> -class iterator_adaptor - : public iterator_facade<Derived, V', C', R', D'> // see details -{ - friend class iterator_core_access; - public: - iterator_adaptor(); - explicit iterator_adaptor(Base const& iter); - typedef Base base_type; - Base const& base() const; - protected: - typedef iterator_adaptor iterator_adaptor_; - Base const& base_reference() const; - Base& base_reference(); - private: // Core iterator interface for iterator_facade. - typename iterator_adaptor::reference dereference() const; - - template < - class OtherDerived, class OtherIterator, class V, class C, class R, class D - > - bool equal(iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D> const& x) const; - - void advance(typename iterator_adaptor::difference_type n); - void increment(); - void decrement(); - - template < - class OtherDerived, class OtherIterator, class V, class C, class R, class D - > - typename iterator_adaptor::difference_type distance_to( - iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D> const& y) const; - - private: - Base m_iterator; // exposition only -}; --
static_cast<Derived*>(iterator_adaptor*) shall be well-formed. -The Base argument shall be Assignable and Copy Constructible.
-The V', C', R', and D' parameters of the iterator_facade -used as a base class in the summary of iterator_adaptor -above are defined as follows:
--V' = if (Value is use_default) - return iterator_traits<Base>::value_type - else - return Value - -C' = if (CategoryOrTraversal is use_default) - return iterator_traversal<Base>::type - else - return CategoryOrTraversal - -R' = if (Reference is use_default) - if (Value is use_default) - return iterator_traits<Base>::reference - else - return Value& - else - return Reference - -D' = if (Difference is use_default) - return iterator_traits<Base>::difference_type - else - return Difference -- - - -
iterator_adaptor();
-Requires: | The Base type must be Default Constructible. | -
---|---|
Returns: | An instance of iterator_adaptor with -m_iterator default constructed. | -
explicit iterator_adaptor(Base const& iter);
-Returns: | An instance of iterator_adaptor with -m_iterator copy constructed from iter. | -
---|
Base const& base() const;
-Returns: | m_iterator | -
---|
Base const& base_reference() const;
-Returns: | A const reference to m_iterator. | -
---|
Base& base_reference();
-Returns: | A non-const reference to m_iterator. | -
---|
typename iterator_adaptor::reference dereference() const;
-Returns: | *m_iterator | -
---|
-template < -class OtherDerived, class OtherIterator, class V, class C, class R, class D -> -bool equal(iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D> const& x) const; --
Returns: | m_iterator == x.base() | -
---|
void advance(typename iterator_adaptor::difference_type n);
-Effects: | m_iterator += n; | -
---|
void increment();
-Effects: | ++m_iterator; | -
---|
void decrement();
-Effects: | --m_iterator; | -
---|
-template < - class OtherDerived, class OtherIterator, class V, class C, class R, class D -> -typename iterator_adaptor::difference_type distance_to( - iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D> const& y) const; --
Returns: | y.base() - m_iterator | -
---|
In this section we'll further refine the node_iter class -template we developed in the iterator_facade tutorial. If you haven't already -read that material, you should go back now and check it out because -we're going to pick up right where it left off.
- -You probably didn't think of it this way, but the node_base* -object that underlies node_iterator is itself an iterator, -just like all other pointers. If we examine that pointer closely -from an iterator perspective, we can see that it has much in common -with the node_iterator we're building. First, they share most -of the same associated types (value_type, reference, -pointer, and difference_type). Second, even some of the -core functionality is the same: operator* and operator== on -the node_iterator return the result of invoking the same -operations on the underlying pointer, via the node_iterator's -dereference and equal member functions). The only real behavioral difference -between node_base* and node_iterator can be observed when -they are incremented: node_iterator follows the -m_next pointer, while node_base* just applies an address offset.
-It turns out that the pattern of building an iterator on another -iterator-like type (the Base [1] type) while modifying -just a few aspects of the underlying type's behavior is an -extremely common one, and it's the pattern addressed by -iterator_adaptor. Using iterator_adaptor is very much like -using iterator_facade, but because iterator_adaptor tries to -mimic as much of the Base type's behavior as possible, we -neither have to supply a Value argument, nor implement any core -behaviors other than increment. The implementation of -node_iter is thus reduced to:
--template <class Value> -class node_iter - : public boost::iterator_adaptor< - node_iter<Value> // Derived - , Value* // Base - , boost::use_default // Value - , boost::forward_traversal_tag // CategoryOrTraversal - > -{ - private: - struct enabler {}; // a private type avoids misuse - - public: - node_iter() - : node_iter::iterator_adaptor_(0) {} - - explicit node_iter(Value* p) - : node_iter::iterator_adaptor_(p) {} - - template <class OtherValue> - node_iter( - node_iter<OtherValue> const& other - , typename boost::enable_if< - boost::is_convertible<OtherValue*,Value*> - , enabler - >::type = enabler() - ) - : node_iter::iterator_adaptor_(other.base()) {} - - private: - friend class boost::iterator_core_access; - void increment() { this->base_reference() = this->base()->next(); } -}; --
Note the use of node_iter::iterator_adaptor_ here: because -iterator_adaptor defines a nested iterator_adaptor_ type -that refers to itself, that gives us a convenient way to refer to -the complicated base class type of node_iter<Value>. [Note: -this technique is known not to work with Borland C++ 5.6.4 and -Metrowerks CodeWarrior versions prior to 9.0]
-You can see an example program that exercises this version of the -node iterators here.
-In the case of node_iter, it's not very compelling to pass -boost::use_default as iterator_adaptor's Value -argument; we could have just passed node_iter's Value -along to iterator_adaptor, and that'd even be shorter! Most -iterator class templates built with iterator_adaptor are -parameterized on another iterator type, rather than on its -value_type. For example, boost::reverse_iterator takes an -iterator type argument and reverses its direction of traversal, -since the original iterator and the reversed one have all the same -associated types, iterator_adaptor's delegation of default -types to its Base saves the implementor of -boost::reverse_iterator from writing:
--std::iterator_traits<Iterator>::some-associated-type --
at least four times.
-We urge you to review the documentation and implementations of -reverse_iterator and the other Boost specialized iterator -adaptors to get an idea of the sorts of things you can do with -iterator_adaptor. In particular, have a look at -transform_iterator, which is perhaps the most straightforward -adaptor, and also counting_iterator, which demonstrates that -iterator_adaptor's Base type needn't be an iterator.
-Author: | -David Abrahams, Jeremy Siek, Thomas Witt |
---|---|
Contact: | -dave@boost-consulting.com, jsiek@osl.iu.edu, witt@styleadvisor.com |
Organization: | -Boost Consulting, Indiana University Open Systems -Lab, Zephyr Associates, Inc. |
Date: | -2004-11-01 |
Copyright: | -Copyright David Abrahams, Jeremy Siek, and Thomas Witt 2004. |
abstract: | The iterator_archetype class constructs a minimal implementation of -one of the iterator access concepts and one of the iterator traversal concepts. -This is used for doing a compile-time check to see if a the type requirements -of a template are really enough to cover the implementation of the template. -For further information see the documentation for the boost::concept_check library. | -
---|
-namespace iterator_archetypes -{ - // Access categories - - typedef /*implementation defined*/ readable_iterator_t; - typedef /*implementation defined*/ writable_iterator_t; - typedef /*implementation defined*/ readable_writable_iterator_t; - typedef /*implementation defined*/ readable_lvalue_iterator_t; - typedef /*implementation defined*/ writable_lvalue_iterator_t; - -} - -template < - class Value - , class AccessCategory - , class TraversalCategory -> -class iterator_archetype -{ - typedef /* see below */ value_type; - typedef /* see below */ reference; - typedef /* see below */ pointer; - typedef /* see below */ difference_type; - typedef /* see below */ iterator_category; -}; --
The access category types provided correspond to the following -standard iterator access concept combinations:
--readable_iterator_t := - - Readable Iterator - -writable_iterator_t := - - Writeable Iterator - -readable_writable_iterator_t := - - Readable Iterator & Writeable Iterator & Swappable Iterator - -readable_lvalue_iterator_t := - - Readable Iterator & Lvalue Iterator - -writeable_lvalue_iterator_t := - - Readable Iterator & Writeable Iterator & Swappable Iterator & Lvalue Iterator --
The AccessCategory argument must be one of the predefined access -category tags. The TraversalCategory must be one of the standard -traversal tags. The Value type must satisfy the requirements of -the iterator concept specified by AccessCategory and -TraversalCategory as implied by the nested traits types.
-iterator_archetype models the iterator concepts specified by the -AccessCategory and TraversalCategory -arguments. iterator_archetype does not model any other access -concepts or any more derived traversal concepts.
-The nested trait types are defined as follows:
--if (AccessCategory == readable_iterator_t) - - value_type = Value - reference = Value - pointer = Value* - -else if (AccessCategory == writable_iterator_t) - - value_type = void - reference = void - pointer = void - -else if (AccessCategory == readable_writable_iterator_t) - - value_type = Value - - reference := - - A type X that is convertible to Value for which the following - expression is valid. Given an object x of type X and v of type - Value. - - x = v - - pointer = Value* - -else if (AccessCategory == readable_lvalue_iterator_t) - - value_type = Value - reference = Value const& - pointer = Value const* - -else if (AccessCategory == writable_lvalue_iterator_t) - - value_type = Value - reference = Value& - pointer = Value* - -if ( TraversalCategory is convertible to forward_traversal_tag ) - - difference_type := ptrdiff_t - -else - - difference_type := unspecified type - - -iterator_category := - - A type X satisfying the following two constraints: - - 1. X is convertible to X1, and not to any more-derived - type, where X1 is defined by: - - if (reference is a reference type - && TraversalCategory is convertible to forward_traversal_tag) - { - if (TraversalCategory is convertible to random_access_traversal_tag) - X1 = random_access_iterator_tag - else if (TraversalCategory is convertible to bidirectional_traversal_tag) - X1 = bidirectional_iterator_tag - else - X1 = forward_iterator_tag - } - else - { - if (TraversalCategory is convertible to single_pass_traversal_tag - && reference != void) - X1 = input_iterator_tag - else - X1 = output_iterator_tag - } - - 2. X is convertible to TraversalCategory --
Author: | -David Abrahams, Jeremy Siek, Thomas Witt |
---|---|
Contact: | -dave@boost-consulting.com, jsiek@osl.iu.edu, witt@styleadvisor.com |
Organization: | -Boost Consulting, Indiana University Open Systems -Lab, Zephyr Associates, Inc. |
Date: | -2004-11-01 |
Copyright: | -Copyright David Abrahams, Jeremy Siek, and Thomas Witt 2004. |
abstract: | The iterator concept checking classes provide a mechanism for -a template to report better error messages when a user instantiates -the template with a type that does not meet the requirements of -the template. | -
---|
For an introduction to using concept checking classes, see -the documentation for the boost::concept_check library.
--namespace boost_concepts { - - // Iterator Access Concepts - - template <typename Iterator> - class ReadableIteratorConcept; - - template < - typename Iterator - , typename ValueType = std::iterator_traits<Iterator>::value_type - > - class WritableIteratorConcept; - - template <typename Iterator> - class SwappableIteratorConcept; - - template <typename Iterator> - class LvalueIteratorConcept; - - // Iterator Traversal Concepts - - template <typename Iterator> - class IncrementableIteratorConcept; - - template <typename Iterator> - class SinglePassIteratorConcept; - - template <typename Iterator> - class ForwardTraversalConcept; - - template <typename Iterator> - class BidirectionalTraversalConcept; - - template <typename Iterator> - class RandomAccessTraversalConcept; - - // Interoperability - - template <typename Iterator, typename ConstIterator> - class InteroperableIteratorConcept; - -} --
Author: | -David Abrahams, Jeremy Siek, Thomas Witt |
---|---|
Contact: | -dave@boost-consulting.com, jsiek@osl.iu.edu, witt@ive.uni-hannover.de |
Organization: | -Boost Consulting, Indiana University Open Systems -Lab, University of Hanover Institute for Transport -Railway Operation and Construction |
Date: | -2004-11-01 |
Copyright: | -Copyright David Abrahams, Jeremy Siek, and Thomas Witt 2003. |
abstract: | - - -iterator_facade is a base class template that implements the -interface of standard iterators in terms of a few core functions -and associated types, to be supplied by a derived iterator class. | -
---|
While the iterator interface is rich, there is a core subset of the -interface that is necessary for all the functionality. We have -identified the following core behaviors for iterators:
-In addition to the behaviors listed above, the core interface elements -include the associated types exposed through iterator traits: -value_type, reference, difference_type, and -iterator_category.
-Iterator facade uses the Curiously Recurring Template -Pattern (CRTP) [Cop95] so that the user can specify the behavior -of iterator_facade in a derived class. Former designs used -policy objects to specify the behavior, but that approach was -discarded for several reasons:
----
-- the creation and eventual copying of the policy object may create -overhead that can be avoided with the current approach.
-- The policy object approach does not allow for custom constructors -on the created iterator types, an essential feature if -iterator_facade should be used in other library -implementations.
-- Without the use of CRTP, the standard requirement that an -iterator's operator++ returns the iterator type itself -would mean that all iterators built with the library would -have to be specializations of iterator_facade<...>, rather -than something more descriptive like -indirect_iterator<T*>. Cumbersome type generator -metafunctions would be needed to build new parameterized -iterators, and a separate iterator_adaptor layer would be -impossible.
-
The user of iterator_facade derives his iterator class from a -specialization of iterator_facade and passes the derived -iterator class as iterator_facade's first template parameter. -The order of the other template parameters have been carefully -chosen to take advantage of useful defaults. For example, when -defining a constant lvalue iterator, the user can pass a -const-qualified version of the iterator's value_type as -iterator_facade's Value parameter and omit the -Reference parameter which follows.
-The derived iterator class must define member functions implementing -the iterator's core behaviors. The following table describes -expressions which are required to be valid depending on the category -of the derived iterator type. These member functions are described -briefly below and in more detail in the iterator facade -requirements.
--- --
-- - -- - - - - Expression -Effects -- i.dereference() -Access the value referred to -- i.equal(j) -Compare for equality with j -- i.increment() -Advance by one position -- i.decrement() -Retreat by one position -- i.advance(n) -Advance by n positions -- - i.distance_to(j) -Measure the distance to j -
In addition to implementing the core interface functions, an iterator -derived from iterator_facade typically defines several -constructors. To model any of the standard iterator concepts, the -iterator must at least have a copy constructor. Also, if the iterator -type X is meant to be automatically interoperate with another -iterator type Y (as with constant and mutable iterators) then -there must be an implicit conversion from X to Y or from Y -to X (but not both), typically implemented as a conversion -constructor. Finally, if the iterator is to model Forward Traversal -Iterator or a more-refined iterator concept, a default constructor is -required.
-iterator_facade and the operator implementations need to be able -to access the core member functions in the derived class. Making the -core member functions public would expose an implementation detail to -the user. The design used here ensures that implementation details do -not appear in the public interface of the derived iterator type.
-Preventing direct access to the core member functions has two -advantages. First, there is no possibility for the user to accidently -use a member function of the iterator when a member of the value_type -was intended. This has been an issue with smart pointer -implementations in the past. The second and main advantage is that -library implementers can freely exchange a hand-rolled iterator -implementation for one based on iterator_facade without fear of -breaking code that was accessing the public core member functions -directly.
-In a naive implementation, keeping the derived class' core member -functions private would require it to grant friendship to -iterator_facade and each of the seven operators. In order to -reduce the burden of limiting access, iterator_core_access is -provided, a class that acts as a gateway to the core member functions -in the derived iterator class. The author of the derived class only -needs to grant friendship to iterator_core_access to make his core -member functions available to the library.
- - -iterator_core_access will be typically implemented as an empty -class containing only private static member functions which invoke the -iterator core member functions. There is, however, no need to -standardize the gateway protocol. Note that even if -iterator_core_access used public member functions it would not -open a safety loophole, as every core member function preserves the -invariants of the iterator.
-The indexing operator for a generalized iterator presents special -challenges. A random access iterator's operator[] is only -required to return something convertible to its value_type. -Requiring that it return an lvalue would rule out currently-legal -random-access iterators which hold the referenced value in a data -member (e.g. counting_iterator), because *(p+n) is a reference -into the temporary iterator p+n, which is destroyed when -operator[] returns.
-Writable iterators built with iterator_facade implement the -semantics required by the preferred resolution to issue 299 and -adopted by proposal n1550: the result of p[n] is an object -convertible to the iterator's value_type, and p[n] = x is -equivalent to *(p + n) = x (Note: This result object may be -implemented as a proxy containing a copy of p+n). This approach -will work properly for any random-access iterator regardless of the -other details of its implementation. A user who knows more about -the implementation of her iterator is free to implement an -operator[] that returns an lvalue in the derived iterator -class; it will hide the one supplied by iterator_facade from -clients of her iterator.
-The reference type of a readable iterator (and today's input -iterator) need not in fact be a reference, so long as it is -convertible to the iterator's value_type. When the value_type -is a class, however, it must still be possible to access members -through operator->. Therefore, an iterator whose reference -type is not in fact a reference must return a proxy containing a copy -of the referenced value from its operator->.
-The return types for iterator_facade's operator-> and -operator[] are not explicitly specified. Instead, those types -are described in terms of a set of requirements, which must be -satisfied by the iterator_facade implementation.
-[Cop95] | (1, 2) [Coplien, 1995] Coplien, J., Curiously Recurring Template -Patterns, C++ Report, February 1995, pp. 24-27. |
-template < - class Derived - , class Value - , class CategoryOrTraversal - , class Reference = Value& - , class Difference = ptrdiff_t -> -class iterator_facade { - public: - typedef remove_const<Value>::type value_type; - typedef Reference reference; - typedef Value* pointer; - typedef Difference difference_type; - typedef /* see below */ iterator_category; - - reference operator*() const; - /* see below */ operator->() const; - /* see below */ operator[](difference_type n) const; - Derived& operator++(); - Derived operator++(int); - Derived& operator--(); - Derived operator--(int); - Derived& operator+=(difference_type n); - Derived& operator-=(difference_type n); - Derived operator-(difference_type n) const; - protected: - typedef iterator_facade iterator_facade_; -}; - -// Comparison operators -template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type // exposition -operator ==(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); - -template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type -operator !=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); - -template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type -operator <(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); - -template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type -operator <=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); - -template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type -operator >(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); - -template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type -operator >=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); - -// Iterator difference -template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -/* see below */ -operator-(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); - -// Iterator addition -template <class Dr, class V, class TC, class R, class D> -Derived operator+ (iterator_facade<Dr,V,TC,R,D> const&, - typename Derived::difference_type n); - -template <class Dr, class V, class TC, class R, class D> -Derived operator+ (typename Derived::difference_type n, - iterator_facade<Dr,V,TC,R,D> const&); --
The iterator_category member of iterator_facade is
--iterator-category(CategoryOrTraversal, value_type, reference) --
where iterator-category is defined as follows:
--iterator-category(C,R,V) := - if (C is convertible to std::input_iterator_tag - || C is convertible to std::output_iterator_tag - ) - return C - - else if (C is not convertible to incrementable_traversal_tag) - the program is ill-formed - - else return a type X satisfying the following two constraints: - - 1. X is convertible to X1, and not to any more-derived - type, where X1 is defined by: - - if (R is a reference type - && C is convertible to forward_traversal_tag) - { - if (C is convertible to random_access_traversal_tag) - X1 = random_access_iterator_tag - else if (C is convertible to bidirectional_traversal_tag) - X1 = bidirectional_iterator_tag - else - X1 = forward_iterator_tag - } - else - { - if (C is convertible to single_pass_traversal_tag - && R is convertible to V) - X1 = input_iterator_tag - else - X1 = C - } - - 2. category-to-traversal(X) is convertible to the most - derived traversal tag type to which X is also - convertible, and not to any more-derived traversal tag - type. --
[Note: the intention is to allow iterator_category to be one of -the five original category tags when convertibility to one of the -traversal tags would add no information]
- - - -The enable_if_interoperable template used above is for exposition -purposes. The member operators should only be in an overload set -provided the derived types Dr1 and Dr2 are interoperable, -meaning that at least one of the types is convertible to the other. The -enable_if_interoperable approach uses SFINAE to take the operators -out of the overload set when the types are not interoperable. -The operators should behave as-if enable_if_interoperable -were defined to be:
--template <bool, typename> enable_if_interoperable_impl -{}; - -template <typename T> enable_if_interoperable_impl<true,T> -{ typedef T type; }; - -template<typename Dr1, typename Dr2, typename T> -struct enable_if_interoperable - : enable_if_interoperable_impl< - is_convertible<Dr1,Dr2>::value || is_convertible<Dr2,Dr1>::value - , T - > -{}; --
The following table describes the typical valid expressions on -iterator_facade's Derived parameter, depending on the -iterator concept(s) it will model. The operations in the first -column must be made accessible to member functions of class -iterator_core_access. In addition, -static_cast<Derived*>(iterator_facade*) shall be well-formed.
-In the table below, F is iterator_facade<X,V,C,R,D>, a is an -object of type X, b and c are objects of type const X, -n is an object of F::difference_type, y is a constant -object of a single pass iterator type interoperable with X, and z -is a constant object of a random access traversal iterator type -interoperable with X.
-iterator_facade Core Operations
-Expression | -Return Type | -Assertion/Note | -Used to implement Iterator -Concept(s) | -
---|---|---|---|
c.dereference() | -F::reference | -- | Readable Iterator, Writable -Iterator | -
c.equal(y) | -convertible to bool | -true iff c and y -refer to the same -position. | -Single Pass Iterator | -
a.increment() | -unused | -- | Incrementable Iterator | -
a.decrement() | -unused | -- | Bidirectional Traversal -Iterator | -
a.advance(n) | -unused | -- | Random Access Traversal -Iterator | -
c.distance_to(z) | -convertible to -F::difference_type | -equivalent to -distance(c, X(z)). | -Random Access Traversal -Iterator | -
The operations in this section are described in terms of operations on -the core interface of Derived which may be inaccessible -(i.e. private). The implementation should access these operations -through member functions of class iterator_core_access.
-reference operator*() const;
-Returns: | static_cast<Derived const*>(this)->dereference() | -
---|
operator->() const; (see below)
-Returns: | If reference is a reference type, an object -of type pointer equal to: --&static_cast<Derived const*>(this)->dereference() -- Otherwise returns an object of unspecified type such that, -(*static_cast<Derived const*>(this))->m is equivalent to (w = **static_cast<Derived const*>(this), -w.m) for some temporary object w of type value_type. - |
-
---|
unspecified operator[](difference_type n) const;
-Returns: | an object convertible to value_type. For constant -objects v of type value_type, and n of type -difference_type, (*this)[n] = v is equivalent to -*(*this + n) = v, and static_cast<value_type -const&>((*this)[n]) is equivalent to -static_cast<value_type const&>(*(*this + n)) | -
---|
Derived& operator++();
-Effects: | -static_cast<Derived*>(this)->increment(); -return *static_cast<Derived*>(this); -- |
-
---|
Derived operator++(int);
-Effects: | -Derived tmp(static_cast<Derived const*>(this)); -++*this; -return tmp; -- |
-
---|
Derived& operator--();
-Effects: | -static_cast<Derived*>(this)->decrement(); -return *static_cast<Derived*>(this); -- |
-
---|
Derived operator--(int);
-Effects: | -Derived tmp(static_cast<Derived const*>(this)); ---*this; -return tmp; -- |
-
---|
Derived& operator+=(difference_type n);
-Effects: | -static_cast<Derived*>(this)->advance(n); -return *static_cast<Derived*>(this); -- |
-
---|
Derived& operator-=(difference_type n);
-Effects: | -static_cast<Derived*>(this)->advance(-n); -return *static_cast<Derived*>(this); -- |
-
---|
Derived operator-(difference_type n) const;
-Effects: | -Derived tmp(static_cast<Derived const*>(this)); -return tmp -= n; -- |
-
---|
-template <class Dr, class V, class TC, class R, class D> -Derived operator+ (iterator_facade<Dr,V,TC,R,D> const&, - typename Derived::difference_type n); - -template <class Dr, class V, class TC, class R, class D> -Derived operator+ (typename Derived::difference_type n, - iterator_facade<Dr,V,TC,R,D> const&); --
Effects: | -Derived tmp(static_cast<Derived const*>(this)); -return tmp += n; -- |
-
---|
-template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type -operator ==(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); --
Returns: | if is_convertible<Dr2,Dr1>::value -
|
-
---|
-template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type -operator !=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); --
Returns: | if is_convertible<Dr2,Dr1>::value -
|
-
---|
-template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type -operator <(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); --
Returns: | if is_convertible<Dr2,Dr1>::value -
|
-
---|
-template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type -operator <=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); --
Returns: | if is_convertible<Dr2,Dr1>::value -
|
-
---|
-template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type -operator >(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); --
Returns: | if is_convertible<Dr2,Dr1>::value -
|
-
---|
-template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,bool>::type -operator >=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); --
Returns: | if is_convertible<Dr2,Dr1>::value -
|
-
---|
-template <class Dr1, class V1, class TC1, class R1, class D1, - class Dr2, class V2, class TC2, class R2, class D2> -typename enable_if_interoperable<Dr1,Dr2,difference>::type -operator -(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, - iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); --
Return Type: | if is_convertible<Dr2,Dr1>::value --- |
-
---|---|
Returns: | if is_convertible<Dr2,Dr1>::value -
|
-
In this section we'll walk through the implementation of a few -iterators using iterator_facade, based around the simple -example of a linked list of polymorphic objects. This example was -inspired by a posting by Keith Macdonald on the Boost-Users -mailing list.
-Say we've written a polymorphic linked list node base class:
--# include <iostream> - -struct node_base -{ - node_base() : m_next(0) {} - - // Each node manages all of its tail nodes - virtual ~node_base() { delete m_next; } - - // Access the rest of the list - node_base* next() const { return m_next; } - - // print to the stream - virtual void print(std::ostream& s) const = 0; - - // double the value - virtual void double_me() = 0; - - void append(node_base* p) - { - if (m_next) - m_next->append(p); - else - m_next = p; - } - - private: - node_base* m_next; -}; --
Lists can hold objects of different types by linking together -specializations of the following template:
--template <class T> -struct node : node_base -{ - node(T x) - : m_value(x) - {} - - void print(std::ostream& s) const { s << this->m_value; } - void double_me() { m_value += m_value; } - - private: - T m_value; -}; --
And we can print any node using the following streaming operator:
--inline std::ostream& operator<<(std::ostream& s, node_base const& n) -{ - n.print(s); - return s; -} --
Our first challenge is to build an appropriate iterator over these -lists.
-We will construct a node_iterator class using inheritance from -iterator_facade to implement most of the iterator's operations.
--# include "node.hpp" -# include <boost/iterator/iterator_facade.hpp> - -class node_iterator - : public boost::iterator_facade<...> -{ - ... -}; --
iterator_facade has several template parameters, so we must decide -what types to use for the arguments. The parameters are Derived, -Value, CategoryOrTraversal, Reference, and Difference.
-Because iterator_facade is meant to be used with the CRTP -[Cop95] the first parameter is the iterator class name itself, -node_iterator.
-The Value parameter determines the node_iterator's -value_type. In this case, we are iterating over node_base -objects, so Value will be node_base.
-Now we have to determine which iterator traversal concept our -node_iterator is going to model. Singly-linked lists only have -forward links, so our iterator can't can't be a bidirectional -traversal iterator. Our iterator should be able to make multiple -passes over the same linked list (unlike, say, an -istream_iterator which consumes the stream it traverses), so it -must be a forward traversal iterator. Therefore, we'll pass -boost::forward_traversal_tag in this position [1].
-[1] | iterator_facade also supports old-style category -tags, so we could have passed std::forward_iterator_tag here; -either way, the resulting iterator's iterator_category will -end up being std::forward_iterator_tag. |
The Reference argument becomes the type returned by -node_iterator's dereference operation, and will also be the -same as std::iterator_traits<node_iterator>::reference. The -library's default for this parameter is Value&; since -node_base& is a good choice for the iterator's reference -type, we can omit this argument, or pass use_default.
-The Difference argument determines how the distance between -two node_iterators will be measured and will also be the -same as std::iterator_traits<node_iterator>::difference_type. -The library's default for Difference is std::ptrdiff_t, an -appropriate type for measuring the distance between any two -addresses in memory, and one that works for almost any iterator, -so we can omit this argument, too.
-The declaration of node_iterator will therefore look something -like:
--# include "node.hpp" -# include <boost/iterator/iterator_facade.hpp> - -class node_iterator - : public boost::iterator_facade< - node_iterator - , node_base - , boost::forward_traversal_tag - > -{ - ... -}; --
Next we need to decide how to represent the iterator's position. -This representation will take the form of data members, so we'll -also need to write constructors to initialize them. The -node_iterator's position is quite naturally represented using -a pointer to a node_base. We'll need a constructor to build an -iterator from a node_base*, and a default constructor to -satisfy the forward traversal iterator requirements [2]. -Our node_iterator then becomes:
--# include "node.hpp" -# include <boost/iterator/iterator_facade.hpp> - -class node_iterator - : public boost::iterator_facade< - node_iterator - , node_base - , boost::forward_traversal_tag - > -{ - public: - node_iterator() - : m_node(0) - {} - - explicit node_iterator(node_base* p) - : m_node(p) - {} - - private: - ... - node_base* m_node; -}; --
[2] | Technically, the C++ standard places almost no -requirements on a default-constructed iterator, so if we were -really concerned with efficiency, we could've written the -default constructor to leave m_node uninitialized. |
The last step is to implement the core operations required by -the concepts we want our iterator to model. Referring to the -table, we can see that the first three rows are applicable -because node_iterator needs to satisfy the requirements for -readable iterator, single pass iterator, and incrementable -iterator.
-We therefore need to supply dereference, -equal, and increment members. We don't want these members -to become part of node_iterator's public interface, so we can -make them private and grant friendship to -boost::iterator_core_access, a "back-door" that -iterator_facade uses to get access to the core operations:
--# include "node.hpp" -# include <boost/iterator/iterator_facade.hpp> - -class node_iterator - : public boost::iterator_facade< - node_iterator - , node_base - , boost::forward_traversal_tag - > -{ - public: - node_iterator() - : m_node(0) {} - - explicit node_iterator(node_base* p) - : m_node(p) {} - - private: - friend class boost::iterator_core_access; - - void increment() { m_node = m_node->next(); } - - bool equal(node_iterator const& other) const - { - return this->m_node == other.m_node; - } - - node_base& dereference() const { return *m_node; } - - node_base* m_node; -}; --
Voilà ; a complete and conforming readable, forward-traversal -iterator! For a working example of its use, see this program.
-Now, our node_iterator gives clients access to both node's print(std::ostream&) const member function, but also its -mutating double_me() member. If we wanted to build a -constant node_iterator, we'd only have to make three -changes:
--class const_node_iterator - : public boost::iterator_facade< - const_node_iterator - , node_base const - , boost::forward_traversal_tag - > -{ - public: - const_node_iterator() - : m_node(0) {} - - explicit const_node_iterator(node_base* p) - : m_node(p) {} - - private: - friend class boost::iterator_core_access; - - void increment() { m_node = m_node->next(); } - - bool equal(const_node_iterator const& other) const - { - return this->m_node == other.m_node; - } - - node_base const& dereference() const { return *m_node; } - - node_base const* m_node; -}; -- -
As a matter of fact, node_iterator and const_node_iterator -are so similar that it makes sense to factor the common code out -into a template as follows:
--template <class Value> -class node_iter - : public boost::iterator_facade< - node_iter<Value> - , Value - , boost::forward_traversal_tag - > -{ - public: - node_iter() - : m_node(0) {} - - explicit node_iter(Value* p) - : m_node(p) {} - - private: - friend class boost::iterator_core_access; - - bool equal(node_iter<Value> const& other) const - { - return this->m_node == other.m_node; - } - - void increment() - { m_node = m_node->next(); } - - Value& dereference() const - { return *m_node; } - - Value* m_node; -}; -typedef node_iter<node_base> node_iterator; -typedef node_iter<node_base const> node_const_iterator; --
Our const_node_iterator works perfectly well on its own, but -taken together with node_iterator it doesn't quite meet -expectations. For example, we'd like to be able to pass a -node_iterator where a node_const_iterator was expected, -just as you can with std::list<int>'s iterator and -const_iterator. Furthermore, given a node_iterator and a -node_const_iterator into the same list, we should be able to -compare them for equality.
-This expected ability to use two different iterator types together -is known as interoperability. Achieving interoperability in -our case is as simple as templatizing the equal function and -adding a templatized converting constructor [3] [4]:
--template <class Value> -class node_iter - : public boost::iterator_facade< - node_iter<Value> - , Value - , boost::forward_traversal_tag - > -{ - public: - node_iter() - : m_node(0) {} - - explicit node_iter(Value* p) - : m_node(p) {} - - template <class OtherValue> - node_iter(node_iter<OtherValue> const& other) - : m_node(other.m_node) {} - - private: - friend class boost::iterator_core_access; - template <class> friend class node_iter; - - template <class OtherValue> - bool equal(node_iter<OtherValue> const& other) const - { - return this->m_node == other.m_node; - } - - void increment() - { m_node = m_node->next(); } - - Value& dereference() const - { return *m_node; } - - Value* m_node; -}; -typedef impl::node_iterator<node_base> node_iterator; -typedef impl::node_iterator<node_base const> node_const_iterator; --
[3] | If you're using an older compiler and it can't handle -this example, see the example code for workarounds. |
[4] | If node_iterator had been a random access -traversal iterator, we'd have had to templatize its -distance_to function as well. |
You can see an example program which exercises our interoperable -iterators here.
-Now node_iterator and node_const_iterator behave exactly as -you'd expect... almost. We can compare them and we can convert in -one direction: from node_iterator to node_const_iterator. -If we try to convert from node_const_iterator to -node_iterator, we'll get an error when the converting -constructor tries to initialize node_iterator's m_node, a -node* with a node const*. So what's the problem?
-The problem is that -boost::is_convertible<node_const_iterator,node_iterator>::value -will be true, but it should be false. is_convertible -lies because it can only see as far as the declaration of -node_iter's converting constructor, but can't look inside at -the definition to make sure it will compile. A perfect solution -would make node_iter's converting constructor disappear when -the m_node conversion would fail.
-In fact, that sort of magic is possible using -boost::enable_if. By rewriting the converting constructor as -follows, we can remove it from the overload set when it's not -appropriate:
--#include <boost/type_traits/is_convertible.hpp> -#include <boost/utility/enable_if.hpp> - - ... - -private: - struct enabler {}; - -public: - template <class OtherValue> - node_iter( - node_iter<OtherValue> const& other - , typename boost::enable_if< - boost::is_convertible<OtherValue*,Value*> - , enabler - >::type = enabler() - ) - : m_node(other.m_node) {} --
This concludes our iterator_facade tutorial, but before you -stop reading we urge you to take a look at iterator_adaptor. -There's another way to approach writing these iterators which might -even be superior.
-