utility/iterator_adaptors.htm
Jeremy Siek 84f1ffdefe added section on Members to cover constructors, etc. and added
a section on Operators


[SVN r9206]
2001-02-15 06:41:46 +00:00

543 lines
21 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>
<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;
typedef Policies policies_type;
iterator_adaptor();
iterator_adaptor(const Base&amp;, const Policies&amp; = Policies());
base_type base() const;
template &lt;class B, class V, class R, class P&gt;
iterator_adaptor (
const iterator_adaptor&lt;B,Policies,V,R,P,Category,Distance&gt;&amp;);
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 P, class V, class R, class Ptr,
class C, class D1, class D2&gt;
iterator_adaptor&lt;B,P,V,R,Ptr,C,D1&gt;
operator+(iterator_adaptor&lt;B,P,V,R,Ptr,C,D1&gt;, D2);
template &lt;class B, class P, class V, class R, class Ptr,
class C, class D1, class D2&gt;
iterator_adaptor&lt;B,P,V,R,P,C,D1&gt;
operator+(D2, iterator_adaptor&lt;B,P,V,R,Ptr,C,D1&gt; p);
template &lt;class B1, class B2, class P, 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 P, 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;);
// and similarly for operators !=, <, <=, >=, >
</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 the 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
<a href="../../more/generic_programming.html#concept">
concept</a> 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>. The first template parameter of the generator will
be the type of the function object and the second will be the base
iterator type. Inside the <tt>transform_iterator_generator</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><tt>Base</tt>
<td>The type being wrapped.
<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.<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>Model of</h3>
Depending on the <tt>Base</tt> and <tt>Policies</tt> template
parameters, an <tt>iterator_adaptor</tt> can be a <a
href="http://www.sgi.com/tech/stl/InputIterator.html"> Input
Iterator</a>, <a
href="http://www.sgi.com/tech/stl/ForwardIterator.html"> Forward
Iterator</a>, <a
href="http://www.sgi.com/tech/stl/BidirectionalIterator.html">
Bidirectional Iterator</a>, or <a
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">
Random Access Iterator</a>.
<h3>Members</h3>
In addition to all of the member functions required of a <a
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">
Random Access Iterator</a>, the <tt>iterator_adaptor</tt> class
template defines the following members.
<p>
<table border>
<tr><td><tt>
iterator_adaptor(const Base&amp;, const Policies&amp; = Policies())
</tt><br>
Construct an iterator adaptor from a base object and a policies object.
</td></tr>
<tr><td><tt>
template &lt;class B, class V, class R, class P&gt;<br>
iterator_adaptor(const iterator_adaptor&lt;B,Policies,V,R,P,Category,Distance&gt;&amp;)
</tt><br><br>
This constructor allows for conversion from mutable to constant iterator
adaptors. This assumes that the type <tt>B</tt> is convertible to the
type <tt>Base</tt>.
</td></tr>
<tr><td><tt>
base_type base() const;
</tt><br><br>
Return a copy of the base object.
</td></tr>
</table>
<h3>Operators</h3>
The <tt>iterator_adaptor</tt> class defines all of the operators
required of a
<a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">
Random Access Iterator</a>. Also, the operators of the
<tt>iterator_adaptor</tt> class that take two iterator adaptor
arguments (difference and comparisons) are defined in such a way
that the operators work on pairs of <tt>iterator_adaptor</tt>
types that have different template parameters, provided that the
base types of the iterator adaptors are interoperable. The reason
for this is so that mutable and constant versions of an iterator
adaptor can be created that will be interoperable with eachother.
<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.
<h3>Implemenation Notes</h3>
<ul>
<li>The <tt>iterator_adaptor::operator[]</tt> returns by-value
instead of by-reference as might be expected. There are two
reasons for this. First, the C++ standard only requires that
the return type by ``convertible to T'' (Table 76). 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 <tt>operator[]</tt>.</li>
</ul>
<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
-->