diff --git a/iterator_adaptors.htm b/iterator_adaptors.htm index 976870a..fe6cae2 100644 --- a/iterator_adaptors.htm +++ b/iterator_adaptors.htm @@ -1,11 +1,10 @@ + -
-The Iterator Adaptor library allows you transform an arbitrary - ``base'' type into a standard-conforming iterator with the - behaviors you choose. Doing so is especially easy if the - ``base'' type is itself an iterator. The library also - supplies several example adaptors which - apply specific useful behaviors to arbitrary base iterators. +
The Iterator Adaptor library allows you transform an arbitrary ``base'' + type into a standard-conforming iterator with the behaviors you choose. + Doing so is especially easy if the ``base'' type is itself an iterator. The + library also supplies several example adaptors which apply + specific useful behaviors to arbitrary base iterators.
Although iterator_adaptor takes seven template parameters, - defaults have been carefully chosen to minimize the number of parameters you - must supply in most cases, especially if BaseType is an iterator. + defaults have been carefully chosen to minimize the number of parameters + you must supply in most cases, especially if BaseType is an + iterator. -
Parameter | Description | ||
---|---|---|---|
BaseType + | BaseType | The type being wrapped. | |
Policies + | Policies - | A policy class - that supplies core functionality to the resulting iterator. A + | A policy + class that supplies core functionality to the resulting iterator. A detailed description can be found below. |
Value + | Value - | The value_type of the resulting iterator, unless const. If Value is
- const X, a conforming compiler makes the
- value_type non-const X[1]. + | The value_type of the resulting iterator, unless const. If
+ Value is const X, a conforming compiler makes the
+ value_type non-const X[1]. Default: - std::iterator_traits<BaseType>::value_type + std::iterator_traits<BaseType>::value_type |
Pointer + | Pointer | The pointer type of the resulting iterator, and in
particular, the result type of operator->(). - Default: If Value was supplied, then Value*, + Default: If Value was supplied, then Value*, otherwise std::iterator_traits<BaseType>::pointer. | |
Reference + | Reference | The reference type of the resulting iterator, and in
particular, the result type of operator*(). @@ -164,84 +179,113 @@ struct iterator_adaptor; std::iterator_traits<BaseType>::reference is used. | |
Category + | Category | The iterator_category type for the resulting iterator. - Default: - std::iterator_traits<BaseType>::iterator_category + Default: + std::iterator_traits<BaseType>::iterator_category | |
Distance + | Distance | The difference_type for the resulting iterator. - Default: - std::iterator_traits<BaseType>::difference_type + Default: + std::iterator_traits<BaseType>::difference_type |
The main task in using iterator_adaptor is creating an - appropriate Policies class. + appropriate Policies class. The Policies class will + become the functional heart of the iterator adaptor, supplying the core + iterator operations that will determine how your new adaptor class will + behave. The iterator_adaptor template defines all of the operators + required of a Random Access + Iterator. Your Policies class must implement three, four, or + seven of the core iterator operations below depending on the iterator + categories you want it to support. - The Policies class will become the functional heart of the iterator - adaptor, supplying the core iterator operations that will determine how your - new adaptor class will behave. The iterator_adaptor template - defines all of the operators required of a - - Random Access Iterator. - Your Policies class must implement three, four, or seven of the core - iterator operations below depending on the iterator categories you want it to support. +
Operation | Effects | Required for Iterator Categories | |
---|---|---|---|
dereference | returns an element of the iterator's - reference type | Input/ Output/ Forward/ Bidirectional/ Random Access + | Operation - |
equal | tests the iterator for equality + | Effects - | |
increment | increments the iterator + | Required for Iterator Categories - | |
decrement | decrements the iterator | Bidirectional/ Random Access + | |
dereference - | |||
less | imposes a Strict Weak - Ordering relation on the iterator's reference type - | Random - Access + | returns an element of the iterator's reference type - |
distance | measures the distance between iterators + | Input/ Output/ Forward/ Bidirectional/ + Random + Access - | |
advance | adds an integer offset to iterators - + | ||
equal + + | tests the iterator for equality + + | ||
increment + + | increments the iterator + + | ||
decrement + + | decrements the iterator + + | Bidirectional/ + Random + Access + + | |
less + + | imposes a Strict Weak + Ordering relation on the iterator's reference type + + | Random + Access + + | |
distance + + | measures the distance between iterators + + | ||
advance + + | adds an integer offset to iterators |
- - The library also supplies a "trivial" policy class, +
The library also supplies a "trivial" policy class,
default_iterator_policies, which implements all seven of the core
operations in the usual way. If you wish to create an iterator adaptor that
- only changes a few of the base type's behaviors, then you can derive your new
- policy class from default_iterator_policies to avoid
- retyping the usual behaviors. You should also look at
+ only changes a few of the base type's behaviors, then you can derive your
+ new policy class from default_iterator_policies to avoid retyping
+ the usual behaviors. You should also look at
default_iterator_policies as the ``boilerplate'' for your own
- policy classes, defining functions with the same interface. This is the definition of
- default_iterator_policies:
+ policy classes, defining functions with the same interface. This is the
+ definition of default_iterator_policies:
+
-
-
+-+struct default_iterator_policies { @@ -274,82 +318,79 @@ struct default_iterator_policies { return x < y; } };-
Template member functions are used throughout -default_iterator_policies so that it can be employed with a wide range -of iterators. If we had used concrete types above, we'd have tied the usefulness -of default_iterator_policies to a particular range of adapted -iterators. If you follow the same pattern with your Policies classes, -you may achieve the same sort of reusability. +
Template member functions are used throughout + default_iterator_policies so that it can be employed with a wide + range of iterators. If we had used concrete types above, we'd have tied the + usefulness of default_iterator_policies to a particular range of + adapted iterators. If you follow the same pattern with your + Policies classes, you may achieve the same sort of reusability.
iterator_adaptor(const Base&, const Policies& =
+ Policies()) + Construct an adapted iterator from a base object and a policies + object. - -
| ||||
base_type base() const; + + Return a copy of the base object. + |
It is often useful to automatically apply some function to the - value returned by dereferencing an - iterator. The transform - iterator makes it easy to create an iterator adaptor which does - just that. Here we will show how easy it is to implement the - transform iterator using the iterator_adaptor template.
+It is often useful to automatically apply some function to the value + returned by dereferencing an iterator. The transform iterator makes it easy to create + an iterator adaptor which does just that. Here we will show how easy it is + to implement the transform iterator using the iterator_adaptor + template.
We want to be able to adapt a range of iterators and functions, so the policies class will have a template parameter for the function type and it - will have a data member of that type. We know that the function takes - one argument and that we'll need to be able to deduce the - result_type of the function so we can use it for the adapted - iterator's value_type. - - AdaptableUnaryFunction is the - - Concept that fulfills those requirements. + will have a data member of that type. We know that the function takes one + argument and that we'll need to be able to deduce the result_type + of the function so we can use it for the adapted iterator's + value_type. AdaptableUnaryFunction + is the Concept + that fulfills those requirements. -
+
To implement a transform iterator we will only change one of the base
+ iterator's behaviors, so the transform_iterator_policies class can
+ inherit the rest from default_iterator_policies. We will define
+ the dereference() member function, which is used implement
+ operator*() of the adapted iterator. The implementation will
+ dereference the base iterator and apply the function object. The
+ type<Reference> parameter is used to convey the appropriate
+ return type. The complete code for transform_iterator_policies
+ is:
+
- To implement a transform iterator we will only change one of the
- base iterator's behaviors, so the
- transform_iterator_policies class can inherit the rest
- from default_iterator_policies. We will define the
-dereference() member function, which is used implement
-operator*() of the adapted iterator. The implementation will
-dereference the base iterator and apply the function object. The
-type<Reference> parameter is used to convey the appropriate return
-type. The complete code for transform_iterator_policies is:
-
-
+-+template <class AdaptableUnaryFunction> struct transform_iterator_policies : public default_iterator_policies @@ -366,26 +407,26 @@ type. The complete code for transform_iterator_policies is: AdaptableUnaryFunction m_f; };-
- The next step is to use the iterator_adaptor template to construct - the transform iterator type. The nicest way to package the construction of - the transform iterator is to create a type - generator. The first template parameter to the generator will be the - type of the function object and the second will be the base iterator - type. We use +
The next step is to use the iterator_adaptor template to
+ construct the transform iterator type. The nicest way to package the
+ construction of the transform iterator is to create a type generator.
+ The first template parameter to the generator will be the type of the
+ function object and the second will be the base iterator type. We use
iterator_adaptor to define the transform iterator type as a nested
- typedef inside the transform_iterator_generator class. Because the function may return by-value, we must limit the
- iterator_category to Input Iterator,
- and the iterator's reference type cannot be a true reference (the
- standard allows this for input iterators), so in this case we can use few of
- iterator_adaptor's default template arguments.
+ typedef inside the transform_iterator_generator class.
+ Because the function may return by-value, we must limit the
+ iterator_category to Input Iterator, and
+ the iterator's reference type cannot be a true reference (the
+ standard allows this for input iterators), so in this case we can use few
+ of iterator_adaptor's default template arguments.
+
-
-
+ +-+template <class AdaptableUnaryFunction, class Iterator> struct transform_iterator_generator @@ -398,14 +439,16 @@ public: type; };-
As a finishing touch, we will create an object - generator for the transform iterator. This is a function that - makes it more convenient to create a transform iterator. -
-
+-As a finishing touch, we will create an object generator + for the transform iterator. This is a function that makes it more + convenient to create a transform iterator.
+
+ + ++template <class AdaptableUnaryFunction, class Iterator> typename transform_iterator_generator<AdaptableUnaryFunction,Iterator>::type @@ -417,15 +460,15 @@ make_transform_iterator(Iterator base, return result_t(base, f); }-
Here is an example that shows how to use a transform iterator - to iterate through a range of numbers, multiplying each of them by - 2 and printing the result to standard - output. +
Here is an example that shows how to use a transform iterator to iterate
+ through a range of numbers, multiplying each of them by 2 and printing the
+ result to standard output.
+
-
-
+ ++#include <functional> #include <algorithm> @@ -438,78 +481,75 @@ int main(int, char*[]) const int N = sizeof(x)/sizeof(int); std::cout << "multiplying the array by 2:" << std::endl; std::copy(boost::make_transform_iterator(x, std::bind1st(std::multiplies<int>(), 2)), - boost::make_transform_iterator(x + N, std::bind1st(std::multiplies<int>(), 2)), - std::ostream_iterator<int>(std::cout, " ")); + boost::make_transform_iterator(x + N, std::bind1st(std::multiplies<int>(), 2)), + std::ostream_iterator<int>(std::cout, " ")); std::cout << std::endl; return 0; }-This output is: + This output is:2 4 6 8 10 12 14 16-
C++ allows const and - non-const pointers to interact in the following intuitive ways: +
C++ allows const and non-const pointers to interact in + the following intuitive ways: +
There is an unlimited number of ways the the - iterator_adaptors class can be used to create - iterators. One interesting exercise would be to re-implement the - iterators of std::list and std::slist using - iterator_adaptors, where the adapted Iterator - types would be node pointers. - - -
There is an unlimited number of ways the the iterator_adaptors + class can be used to create iterators. One interesting exercise would be to + re-implement the iterators of std::list and std::slist + using iterator_adaptors, where the adapted Iterator types + would be node pointers. +
@@ -540,7 +580,8 @@ struct iterator_adaptor const iterator_adaptor<B,Policies,V,R,P,Category,Distance>&); reference operator*() const; - operator_arrow_result_type operator->() const; [3] + operator_arrow_result_type operator->() const; [3] value_type operator[](difference_type n) const; [4] iterator_adaptor& operator++(); @@ -574,68 +615,72 @@ template <class B1, class B2, class P, class V1, class V2, bool operator==(const iterator_adaptor<B1,P,V1,R1,P1,C,D>&, const iterator_adaptor<B2,P,V2,R2,P2,C,D>&); -// and similarly for operators !=, <, <=, >=, > +// and similarly for operators !=, <, <=, >=, >
[1] If your compiler does not support partial - specialization and the base iterator is a builtin pointer type, - then you will not be able to use the default for Value - and will need to explicitly specify this type. + specialization and the base iterator is a builtin pointer type, then you + will not be able to use the default for Value and will need to + explicitly specify this type.
[2] The standard specifies that the value_type of const iterators to T (e.g. const T*) is non-const T, while the pointer and - reference types for all Forward - Iterators are const T* and const T&, - respectively. Stripping the const-ness of Value is - designed to allow you to easily make a const iterator adaptor by - supplying a const type for Value, and allowing the - defaults for the Pointer and Reference parameters to take - effect. Although compilers that don't support partial specialization won't - do this for you, having a const value_type is often harmless in - practice. - -
[3] The result type for the operator->() - depends on the category and value type of the iterator and - is somewhat complicated to describe. But be assured, it works - in a stardard conforming fashion, providing access to members - of the objects pointed to by the iterator. - -
[4] The result type of operator[]() is value_type - instead of reference as might be expected. There are two - reasons for this choice. First, the C++ standard only requires that the return - type of an arbitrary - - Random Access Iterator's operator[]be ``convertible to T'' - (Table 76), so when adapting an arbitrary base iterator we may not have a - reference to return. Second, and more importantly, for certain kinds of - iterators, returning a reference could cause serious memory problems due to - the reference being bound to a temporary object whose lifetime ends inside - of the operator[]. + reference types for all Forward Iterators + are const T* and const T&, respectively. Stripping + the const-ness of Value is designed to allow you to + easily make a const iterator adaptor by supplying a const + type for Value, and allowing the defaults for the Pointer + and Reference parameters to take effect. Although compilers that + don't support partial specialization won't do this for you, having a + const value_type is often harmless in practice. +
[3] The result type for the operator->() + depends on the category and value type of the iterator and is somewhat + complicated to describe. But be assured, it works in a stardard conforming + fashion, providing access to members of the objects pointed to by the + iterator. +
[4] The result type of operator[]() is + value_type instead of reference as might be expected. + There are two reasons for this choice. First, the C++ standard only + requires that the return type of an arbitrary Random Access + Iterator's operator[]be ``convertible to T'' (Table 76), so + when adapting an arbitrary base iterator we may not have a reference to + return. Second, and more importantly, for certain kinds of iterators, + returning a reference could cause serious memory problems due to the + reference being bound to a temporary object whose lifetime ends inside of + the operator[].
Revised 15 Feb 2001 -
© Copyright Dave Abrahams and Jeremy Siek 2001. Permission to copy, use, modify, sell - and distribute this document is granted provided this copyright notice - appears in all copies. This document is provided "as is" without express or - implied warranty, and with no claim as to its suitability for any purpose. - - - - - - +
© Copyright Dave Abrahams and Jeremy Siek 2001. Permission to copy, + use, modify, sell and distribute this document is granted provided this + copyright notice appears in all copies. This document is provided "as is" + without express or implied warranty, and with no claim as to its + suitability for any purpose. + + + + + + + + + + +