utility/iterator_adaptors.htm
2001-02-13 04:38:59 +00:00

515 lines
20 KiB
HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<meta name="generator" content="HTML Tidy, see www.w3.org">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<body bgcolor="#FFFFFF" text="#000000">
<title>Boost Iterator Adaptor Library</title>
<img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align=
"center" width="277" height="86">
<h1>Boost Iterator Adaptor Library</h1>
<h2>Introduction</h2>
<p>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 <a href=
"../../more/generic_programming.html#adaptors">adaptors</a> which
apply specific useful behaviors to arbitrary base iterators.
<h2>Table of Contents</h2>
<ul>
<li>
Header <tt><a href=
"../../boost/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a></tt>
<ul>
<li>Template class <tt><a href=
"#iterator_adaptor">iterator_adaptor</a></tt>
<li><a href="indirect_iterator.htm">Indirect Iterator Adaptor</a>
<li><a href="reverse_iterator.htm">Reverse Iterator Adaptor</a>
<li><a href="transform_iterator.htm">Transform Iterator Adaptor</a>
<li><a href="projection_iterator.htm">Projection Iterator Adaptor</a>
<li><a href="filter_iterator.htm">Filter Iterator Adaptor</a>
</ul>
<li>Header <tt><a href=
"../../boost/counting_iterator.hpp">boost/counting_iterator.hpp</a></tt><br>
<a href="counting_iterator.htm">Counting Iterator Adaptor</a>
</ul>
<!-- not sure where this paragraph was going...
defines the <tt>iterator_adaptor</tt> class template and several <a href=
"../../more/generic_programming.html#type_generator">type generators</a>
and <a href="../../more/generic_programming.html#object_generator">object
generators</a> which allow you to easily create adapted iterator types. The
Iterator Adaptors
-->
<p><b><a href="http://www.boost.org/people/dave_abrahams.htm">Dave
Abrahams</a></b> started the library, applying <a href=
"../../more/generic_programming.html#policies">policies class</a> technique
and handling const/non-const iterator interactions. He also contributed the
<tt><a href="indirect_iterator.htm">indirect_</a></tt> and <tt><a href=
"reverse_iterator.htm">reverse_</a></tt> iterator generators, and expanded
<tt><a href="counting_iterator.htm">counting_iterator_generator</a></tt> to
cover all incrementable types.<br>
<b><a href="http://www.boost.org/people/jeremy_siek.htm">Jeremy
Siek</a></b> contributed the <a href="transform_iterator.htm">transform
iterator</a> adaptor, the integer-only version of <tt><a href=
"counting_iterator.htm">counting_iterator_generator</a></tt>, and most of
the documentation.<br>
<b><a href="http://www.boost.org/people/john_potter.htm">John
Potter</a></b> contributed the <tt><a href=
"projection_iterator.htm">projection_</a></tt> and <tt><a href=
"filter_iterator.htm">filter_</a></tt> iterator generators and made some
simplifications to the main <tt><a href=
"#iterator_adaptor">iterator_adaptor</a></tt> template.<br>
<h2><a name="iterator_adaptor">Class template</a> <tt>iterator_adaptor</tt></h2>
Implementing standard conforming iterators is a non-trivial task. There are
some fine points such as the interactions between an iterator and its
corresponding const_iterator, and there are myriad operators that should be
implemented but are easily forgotten or mishandled, such as
<tt>operator-&gt;()</tt>. Using <tt>iterator_adaptor</tt>, you can easily
implement an iterator class, and even more easily extend and <a href=
"../../more/generic_programming.html#adaptors">adapt</a> existing iterator
types. Moreover, it is easy to make a pair of interoperable <tt>const</tt>
and <tt>non-const</tt> iterators.
<h3>Synopsis</h3>
<pre>
template &lt;class Base, class Policies,
class Value = typename std::iterator_traits&lt;Base&gt;::value_type,
class Reference = <i>...(see below)</i>,
class Pointer = <i>...(see below)</i>,
class Category = typename std::iterator_traits&lt;Base&gt;::iterator_category,
class Distance = typename std::iterator_traits&lt;Base&gt;::difference_type
&gt;
struct iterator_adaptor;
{
typedef Distance difference_type;
typedef typename boost::remove_const&lt;Value&gt;::type value_type;
typedef Pointer pointer;
typedef Reference reference;
typedef Category iterator_category;
typedef Base base_type;
iterator_adaptor();
iterator_adaptor(const Base&amp;, const Policies&amp; = Policies());
base_type base() const;
template &lt;class Iter2, class Value2, class Pointer2, class Reference2&gt;
iterator_adaptor (
const iterator_adaptor&lt;Iter2,Policies,Value2,Reference2,Pointer2,Category,Distance&gt;&amp;
: m_iter_p(src.iter(), src.policies());
reference operator*() const;
<i>operator_arrow_result_type</i> operator-&gt;() const; <a href="#2">[2]</a>
value_type operator[](difference_type n) const;
iterator_adaptor&amp; operator++();
iterator_adaptor&amp; operator++(int);
iterator_adaptor&amp; operator--();
iterator_adaptor&amp; operator--(int);
iterator_adaptor&amp; operator+=(difference_type n);
iterator_adaptor&amp; operator-=(difference_type n);
iterator_adaptor&amp; operator-(Distance x) const;
};
template &lt;class B, class Policies, class V, class R, class P,
class C, class D1, class D2&gt;
iterator_adaptor&lt;B,Policies,V,R,P,C,D1&gt;
operator+(iterator_adaptor&lt;B,P,V,R,P,C,D1&gt;, D2);
template &lt;class B, class Policies, class V, class R, class P,
class C, class D1, class D2&gt;
iterator_adaptor&lt;B,Policies,V,R,P,C,D1&gt;
operator+(D2, iterator_adaptor&lt;B,P,V,R,P,C,D1&gt; p);
template &lt;class B1, class B2, class Policies, class V1, class V2,
class R1, class R2, class P1, class P2, class C, class D&gt;
Distance operator-(const iterator_adaptor&lt;B1,P,V1,R1,P1,C,D&gt;&amp;,
const iterator_adaptor&lt;B2,P,V2,R2,P2,C,D&gt;&amp;);
template &lt;class B1, class B2, class Policies, class V1, class V2,
class R1, class R2, class P1, class P2, class C, class D&gt;
bool operator==(const iterator_adaptor&lt;B1,P,V1,R1,P1,C,D&gt;&amp;,
const iterator_adaptor&lt;B2,P,V2,R2,P2,C,D&gt;&amp;);
template &lt;class B1, class B2, class Policies, class V1, class V2,
class R1, class R2, class P1, class P2, class C, class D&gt;
bool operator!=(const iterator_adaptor&lt;B1,P,V1,R1,P1,C,D&gt;&amp;,
const iterator_adaptor&lt;B2,P,V2,R2,P2,C,D&gt;&amp;);
template &lt;class B1, class B2, class Policies, class V1, class V2,
class R1, class R2, class P1, class P2, class C, class D&gt;
bool operator&lt;(const iterator_adaptor&lt;B1,P,V1,R1,P1,C,D&gt;&amp;,
const iterator_adaptor&lt;B2,P,V2,R2,P2,C,D&gt;&amp;);
template &lt;class B1, class B2, class Policies, class V1, class V2,
class R1, class R2, class P1, class P2, class C, class D&gt;
bool operator&lt;=(const iterator_adaptor&lt;B1,P,V1,R1,P1,C,D&gt;&amp;,
const iterator_adaptor&lt;B2,P,V2,R2,P2,C,D&gt;&amp;);
template &lt;class B1, class B2, class Policies, class V1, class V2,
class R1, class R2, class P1, class P2, class C, class D&gt;
bool operator&gt;=(const iterator_adaptor&lt;B1,P,V1,R1,P1,C,D&gt;&amp;,
const iterator_adaptor&lt;B2,P,V2,R2,P2,C,D&gt;&amp;);
template &lt;class B1, class B2, class Policies, class V1, class V2,
class R1, class R2, class P1, class P2, class C, class D&gt;
bool operator&gt;(const iterator_adaptor&lt;B1,P,V1,R1,P1,C,D&gt;&amp;,
const iterator_adaptor&lt;B2,P,V2,R2,P2,C,D&gt;&amp;);
</pre>
<h3>Example</h3>
<p>It is often useful to automatically apply some function to the
value returned by dereferencing (<tt>operator*()</tt>) an
iterator. The <a href="./transform_iterator.htm">transform
iterator</a> makes it easy to create an iterator adaptor that does
just that. Here we will show how easy it is to implement the
transform iterator using the <tt>iterator_adaptor</tt> class.</p>
<p>The main task in using <tt>iterator_adaptor</tt> is creating an
appropriate <tt>Policies</tt> class.
The <tt>Policies</tt> class that you pass in will become the heart of
the iterator adaptor, supplying the core iterator operations that will
determine how your new adaptor class will behave. The core iterator
operations are:
<ul>
<li><code>dereference</code> - returns an element of the iterator's
<code>reference</code> type
<li><code>equal</code> - tests the iterator for equality
<li><code>increment</code> - increments the iterator
<li><code>decrement</code> - decrements bidirectional and random-access
iterators
<li><code>less</code> - imposes a strict weak ordering relation on
random-access iterators
<li><code>distance</code> - measures the distance between random-access
iterators
<li><code>advance</code> - adds an integer offset to random-access
iterators
</ul>
The <tt>Policies</tt> class must implement three, four, or seven of the
core iterator operations depending on whether you wish the new iterator
adaptor class to be a <a href=
"http://www.sgi.com/Technology/STL/ForwardIterator.html">ForwardIterator</a>,
<a href=
"http://www.sgi.com/Technology/STL/BidirectionalIterator.html">BidirectionalIterator</a>,
or <a href=
"http://www.sgi.com/Technology/STL/RandomAccessIterator.html">RandomAccessIterator</a>.
The <tt>iterator_category</tt> type of the traits class you pass in must
match the category of iterator that you want to create. The default policy
class, <tt>default_iterator_policies</tt>, implements all 7 of the core
operations in the usual way. If you wish to create an iterator adaptor that
only changes a few of the iterator's behaviors, then you can have your new
policy class inherit from <tt>default_iterator_policies</tt> to avoid
retyping the usual behaviors. You should also look at
<tt>default_iterator_policies</tt> as the ``boiler-plate'' for your own
policy classes. The following is definition of the
<tt>default_iterator_policies</tt> class:
<p>
<blockquote>
<pre>
struct default_iterator_policies
{
// required for a ForwardIterator
template &lt;class Reference, class Iterator&gt;
Reference dereference(type&lt;Reference&gt;, const Iterator&amp; x) const
{ return *x; }
template &lt;class Iterator&gt;
static void increment(Iterator&amp; x)
{ ++x; }
template &lt;class Iterator1, class Iterator2&gt;
bool equal(Iterator1&amp; x, Iterator2&amp; y) const
{ return x == y; }
// required for a BidirectionalIterator
template &lt;class Iterator&gt;
static void decrement(Iterator&amp; x)
{ --x; }
// required for a RandomAccessIterator
template &lt;class Iterator, class DifferenceType&gt;
static void advance(Iterator&amp; x, DifferenceType n)
{ x += n; }
template &lt;class Difference, class Iterator1, class Iterator2&gt;
Difference distance(type&lt;Difference&gt;, Iterator1&amp; x, Iterator2&amp; y) const
{ return y - x; }
template &lt;class Iterator1, class Iterator2&gt;
bool less(Iterator1&amp; x, Iterator2&amp; y) const
{ return x &lt; y; }
};
</pre>
</blockquote>
To implement a transform iterator we will only change one of the
base iterator's behaviors, so the
<tt>transform_iterator_policies</tt> class will inherit the rest
from <tt>default_iterator_policies</tt>. In addition, we will need
a function object to apply, so the policies class will have a
template parameter for the function object and it will have a data
member of that type. The function will take one argument (the
value type of the base iterator) and we will need to know the
<tt>result_type</tt> of the function, so
<a href="http://www.sgi.com/Technology/STL/AdaptableUnaryFunction.html">
AdaptableUnaryFunction</a> is the correct concept (set of
requirements) to choose for the function object type. Inside of
<tt>transform_iterator_policies</tt> we will implement the
<tt>dereference()</tt> member function. This member function will
dereference the base iterator (the second parameter of
<tt>dereference()</tt>) and apply the function object. The
<tt>type&lt;Reference&gt;</tt> class used below is there to convey
the reference type of the iterator, which is handy when writing
generic iterator adaptors such as this one. The following is the
complete code for the <tt>transform_iterator_policies</tt> class.
<p>
<blockquote>
<pre>
template &lt;class AdaptableUnaryFunction&gt;
struct transform_iterator_policies : public default_iterator_policies
{
transform_iterator_policies() { }
transform_iterator_policies(const AdaptableUnaryFunction&amp; f) : m_f(f) { }
template &lt;class Reference, class BaseIterator&gt;
Reference dereference(type&lt;Reference&gt;, const BaseIterator&amp; i) const
{ return m_f(*i); }
AdaptableUnaryFunction m_f;
};
</pre>
</blockquote>
<p>
The next step is to use the <tt>iterator_adaptor</tt> class to
construct the transform iterator type. The nicest way to package
up the construction of the transform iterator is to create a <a
href="../../more/generic_programming.html#type_generator">type
generator</a>, which is a class whose sole purpose is to
create a typedef for some new type based on several template
parameters. The first template parameter will be the type of the
function object and the second will be the base iterator
type. Inside the <tt>transform_iterators</tt> class we use the
<tt>iterator_adaptor</tt> class to create the transform iterator
type.
<p>
<blockquote>
<pre>
template &lt;class AdaptableUnaryFunction, class Iterator&gt;
struct transform_iterator_generator
{
typedef typename AdaptableUnaryFunction::result_type value_type;
public:
typedef iterator_adaptor&lt;Iterator,
transform_iterator_policies&lt;AdaptableUnaryFunction&gt;,
value_type, value_type, value_type*, std::input_iterator_tag&gt;
type;
};
</pre>
</blockquote>
<p>As a finishing touch, we will create an <a
href="../../more/generic_programming.html#object_generator">object
generator</a> for the transform iterator. This is a function that
makes it more convenient to create a transform iterator.
<p>
<blockquote>
<pre>
template &lt;class AdaptableUnaryFunction, class Iterator&gt;
typename transform_iterator_generator&lt;AdaptableUnaryFunction,Iterator&gt;::type
make_transform_iterator(Iterator base,
const AdaptableUnaryFunction&amp; f = AdaptableUnaryFunction())
{
typedef typename transform_iterator_generator&lt;AdaptableUnaryFunction,
Iterator&gt;::type result_t;
return result_t(base, f);
}
</pre>
</blockquote>
<p>The following is an example of how to use a transform iterator
to iterate through a range of numbers, multiplying each of them by
2 when they are dereferenced and printing the result to standard
output.
<p>
<blockquote>
<pre>
#include &lt;functional&gt;
#include &lt;algorithm&gt;
#include &lt;iostream&gt;
#include &lt;boost/iterator_adaptors.hpp&gt;
int main(int, char*[])
{
int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
const int N = sizeof(x)/sizeof(int);
std::cout &lt;&lt; "multiplying the array by 2:" &lt;&lt; std::endl;
std::copy(boost::make_transform_iterator(x, std::bind1st(std::multiplies&lt;int&gt;(), 2)),
boost::make_transform_iterator(x + N, std::bind1st(std::multiplies&lt;int&gt;(), 2)),
std::ostream_iterator&lt;int&gt;(std::cout, " "));
std::cout &lt;&lt; std::endl;
return 0;
}
</pre>
This output is:
<pre>
2 4 6 8 10 12 14 16
</pre>
</blockquote>
<h3>Template Parameters</h3>
<table border>
<tr>
<th>Parameter
<th>Description
<tr>
<td><a href=
"http://www.sgi.com/tech/stl/Predicate.html"><tt>Predicate</tt></a>
<td>The function object that determines which elements are retained and
which elements are skipped.
<tr>
<td><tt>BaseIterator</tt>
<td>The iterator type being wrapped. This type must at least be a model
of the <a href=
"http://www.sgi.com/tech/stl/InputIterator">InputIterator</a> concept.
<tr>
<td><tt>Value</tt>
<td>The <tt>value_type</tt> of the resulting iterator, unless const. If
const, a conforming compiler strips constness for the
<tt>value_type</tt>. Typically the default for this parameter is the
appropriate type<a href="#1">[1]</a>.<br>
<b>Default:</b>
<tt>std::iterator_traits&lt;BaseIterator&gt;::value_type</tt>
<tr>
<td><tt>Pointer</tt>
<td>The <tt>pointer</tt> type of the resulting iterator, and in
particular, the result type of operator-&gt;(). Typically the default
for this parameter is the appropriate type.<br>
<b>Default:</b> If <tt>Value</tt> was supplied, then <tt>Value*</tt>,
otherwise <tt>std::iterator_traits&lt;BaseIterator&gt;::pointer</tt>.
<tr>
<td><tt>Reference</tt>
<td>The <tt>reference</tt> type of the resulting iterator, and in
particular, the result type of operator*(). Typically the default for
this parameter is the appropriate type.<br>
<b>Default:</b> If <tt>Value</tt> is supplied, <tt>Value&amp;</tt> is
used. Otherwise
<tt>std::iterator_traits&lt;BaseIterator&gt;::reference</tt> is used.
<tr>
<td><tt>Category</tt>
<td>The <tt>iterator_category</tt> type for the resulting iterator.
Typically the default for this parameter is the appropriate type. If
you override this parameter, do not use
<tt>bidirectional_iterator_tag</tt> because filter iterators can not go
in reverse.<br>
<b>Default:</b>
<tt>std::iterator_traits&lt;BaseIterator&gt;::iterator_category</tt>
<tr>
<td><tt>Distance</tt>
<td>The <tt>difference_type</tt> for the resulting iterator. Typically
the default for this parameter is the appropriate type.<br>
<b>Default:</b>
<tt>std::iterator_traits&lt;BaseIterator&gt;::difference_type</tt>
</table>
<h3>Challenge</h3>
<p>There is an unlimited number of ways the the
<tt>iterator_adaptors</tt> class can be used to create
iterators. One interesting exercise would be to re-implement the
iterators of <tt>std::list</tt> and <tt>std::slist</tt> using
<tt>iterator_adaptors</tt>, where the adapted <tt>Iterator</tt>
types would be node pointers.
<h3>Notes</h3>
<p><a name="1">[1]</a> 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 <tt>Value</tt>
and will need to explicitly specify this type.
<p><a name="2">[2]</a> The result type for the <tt>operator->()</tt>
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.
<hr>
<p>Revised
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->10
Feb 2001<!--webbot bot="Timestamp" endspan i-checksum="14373" -->
<p>&copy; 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.
</body>
<!-- LocalWords: HTML html charset alt gif abrahams htm const incrementable
-->
<!-- LocalWords: siek mishandled interoperable typename struct Iter iter src
-->
<!-- LocalWords: int bool ForwardIterator BidirectionalIterator BaseIterator
-->
<!-- LocalWords: RandomAccessIterator DifferenceType AdaptableUnaryFunction
-->
<!-- LocalWords: iostream hpp sizeof InputIterator constness ConstIterator
-->