This commit was manufactured by cvs2svn to create branch

'unlabeled-1.8.2'.

[SVN r9368]
This commit is contained in:
nobody
2001-02-28 21:40:00 +00:00
commit fbb3c49f8b
4 changed files with 1606 additions and 0 deletions

96
.gitattributes vendored Normal file
View File

@@ -0,0 +1,96 @@
* text=auto !eol svneol=native#text/plain
*.gitattributes text svneol=native#text/plain
# Scriptish formats
*.bat text svneol=native#text/plain
*.bsh text svneol=native#text/x-beanshell
*.cgi text svneol=native#text/plain
*.cmd text svneol=native#text/plain
*.js text svneol=native#text/javascript
*.php text svneol=native#text/x-php
*.pl text svneol=native#text/x-perl
*.pm text svneol=native#text/x-perl
*.py text svneol=native#text/x-python
*.sh eol=lf svneol=LF#text/x-sh
configure eol=lf svneol=LF#text/x-sh
# Image formats
*.bmp binary svneol=unset#image/bmp
*.gif binary svneol=unset#image/gif
*.ico binary svneol=unset#image/ico
*.jpeg binary svneol=unset#image/jpeg
*.jpg binary svneol=unset#image/jpeg
*.png binary svneol=unset#image/png
*.tif binary svneol=unset#image/tiff
*.tiff binary svneol=unset#image/tiff
*.svg text svneol=native#image/svg%2Bxml
# Data formats
*.pdf binary svneol=unset#application/pdf
*.avi binary svneol=unset#video/avi
*.doc binary svneol=unset#application/msword
*.dsp text svneol=crlf#text/plain
*.dsw text svneol=crlf#text/plain
*.eps binary svneol=unset#application/postscript
*.gz binary svneol=unset#application/gzip
*.mov binary svneol=unset#video/quicktime
*.mp3 binary svneol=unset#audio/mpeg
*.ppt binary svneol=unset#application/vnd.ms-powerpoint
*.ps binary svneol=unset#application/postscript
*.psd binary svneol=unset#application/photoshop
*.rdf binary svneol=unset#text/rdf
*.rss text svneol=unset#text/xml
*.rtf binary svneol=unset#text/rtf
*.sln text svneol=native#text/plain
*.swf binary svneol=unset#application/x-shockwave-flash
*.tgz binary svneol=unset#application/gzip
*.vcproj text svneol=native#text/xml
*.vcxproj text svneol=native#text/xml
*.vsprops text svneol=native#text/xml
*.wav binary svneol=unset#audio/wav
*.xls binary svneol=unset#application/vnd.ms-excel
*.zip binary svneol=unset#application/zip
# Text formats
.htaccess text svneol=native#text/plain
*.bbk text svneol=native#text/xml
*.cmake text svneol=native#text/plain
*.css text svneol=native#text/css
*.dtd text svneol=native#text/xml
*.htm text svneol=native#text/html
*.html text svneol=native#text/html
*.ini text svneol=native#text/plain
*.log text svneol=native#text/plain
*.mak text svneol=native#text/plain
*.qbk text svneol=native#text/plain
*.rst text svneol=native#text/plain
*.sql text svneol=native#text/x-sql
*.txt text svneol=native#text/plain
*.xhtml text svneol=native#text/xhtml%2Bxml
*.xml text svneol=native#text/xml
*.xsd text svneol=native#text/xml
*.xsl text svneol=native#text/xml
*.xslt text svneol=native#text/xml
*.xul text svneol=native#text/xul
*.yml text svneol=native#text/plain
boost-no-inspect text svneol=native#text/plain
CHANGES text svneol=native#text/plain
COPYING text svneol=native#text/plain
INSTALL text svneol=native#text/plain
Jamfile text svneol=native#text/plain
Jamroot text svneol=native#text/plain
Jamfile.v2 text svneol=native#text/plain
Jamrules text svneol=native#text/plain
Makefile* text svneol=native#text/plain
README text svneol=native#text/plain
TODO text svneol=native#text/plain
# Code formats
*.c text svneol=native#text/plain
*.cpp text svneol=native#text/plain
*.h text svneol=native#text/plain
*.hpp text svneol=native#text/plain
*.ipp text svneol=native#text/plain
*.tpp text svneol=native#text/plain
*.jam text svneol=native#text/plain
*.java text svneol=native#text/plain

366
call_traits_test.cpp Normal file
View File

@@ -0,0 +1,366 @@
// boost::compressed_pair test program
// (C) Copyright John Maddock 2000. Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
// standalone test program for <boost/call_traits.hpp>
// 03 Oct 2000:
// Enabled extra tests for VC6.
#include <cassert>
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <typeinfo>
#include <boost/call_traits.hpp>
#include "type_traits_test.hpp"
//
// struct contained models a type that contains a type (for example std::pair)
// arrays are contained by value, and have to be treated as a special case:
//
template <class T>
struct contained
{
// define our typedefs first, arrays are stored by value
// so value_type is not the same as result_type:
typedef typename boost::call_traits<T>::param_type param_type;
typedef typename boost::call_traits<T>::reference reference;
typedef typename boost::call_traits<T>::const_reference const_reference;
typedef T value_type;
typedef typename boost::call_traits<T>::value_type result_type;
// stored value:
value_type v_;
// constructors:
contained() {}
contained(param_type p) : v_(p){}
// return byval:
result_type value()const { return v_; }
// return by_ref:
reference get() { return v_; }
const_reference const_get()const { return v_; }
// pass value:
void call(param_type p){}
};
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
template <class T, std::size_t N>
struct contained<T[N]>
{
typedef typename boost::call_traits<T[N]>::param_type param_type;
typedef typename boost::call_traits<T[N]>::reference reference;
typedef typename boost::call_traits<T[N]>::const_reference const_reference;
typedef T value_type[N];
typedef typename boost::call_traits<T[N]>::value_type result_type;
value_type v_;
contained(param_type p)
{
std::copy(p, p+N, v_);
}
// return byval:
result_type value()const { return v_; }
// return by_ref:
reference get() { return v_; }
const_reference const_get()const { return v_; }
void call(param_type p){}
};
#endif
template <class T>
contained<typename boost::call_traits<T>::value_type> wrap(const T& t)
{
typedef typename boost::call_traits<T>::value_type ct;
return contained<ct>(t);
}
namespace test{
template <class T1, class T2>
std::pair<
typename boost::call_traits<T1>::value_type,
typename boost::call_traits<T2>::value_type>
make_pair(const T1& t1, const T2& t2)
{
return std::pair<
typename boost::call_traits<T1>::value_type,
typename boost::call_traits<T2>::value_type>(t1, t2);
}
} // namespace test
using namespace std;
//
// struct checker:
// verifies behaviour of contained example:
//
template <class T>
struct checker
{
typedef typename boost::call_traits<T>::param_type param_type;
void operator()(param_type);
};
template <class T>
void checker<T>::operator()(param_type p)
{
T t(p);
contained<T> c(t);
cout << "checking contained<" << typeid(T).name() << ">..." << endl;
assert(t == c.value());
assert(t == c.get());
assert(t == c.const_get());
//cout << "typeof contained<" << typeid(T).name() << ">::v_ is: " << typeid(&contained<T>::v_).name() << endl;
cout << "typeof contained<" << typeid(T).name() << ">::value() is: " << typeid(&contained<T>::value).name() << endl;
cout << "typeof contained<" << typeid(T).name() << ">::get() is: " << typeid(&contained<T>::get).name() << endl;
cout << "typeof contained<" << typeid(T).name() << ">::const_get() is: " << typeid(&contained<T>::const_get).name() << endl;
cout << "typeof contained<" << typeid(T).name() << ">::call() is: " << typeid(&contained<T>::call).name() << endl;
cout << endl;
}
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
template <class T, std::size_t N>
struct checker<T[N]>
{
typedef typename boost::call_traits<T[N]>::param_type param_type;
void operator()(param_type t)
{
contained<T[N]> c(t);
cout << "checking contained<" << typeid(T[N]).name() << ">..." << endl;
unsigned int i = 0;
for(i = 0; i < N; ++i)
assert(t[i] == c.value()[i]);
for(i = 0; i < N; ++i)
assert(t[i] == c.get()[i]);
for(i = 0; i < N; ++i)
assert(t[i] == c.const_get()[i]);
cout << "typeof contained<" << typeid(T[N]).name() << ">::v_ is: " << typeid(&contained<T[N]>::v_).name() << endl;
cout << "typeof contained<" << typeid(T[N]).name() << ">::value is: " << typeid(&contained<T[N]>::value).name() << endl;
cout << "typeof contained<" << typeid(T[N]).name() << ">::get is: " << typeid(&contained<T[N]>::get).name() << endl;
cout << "typeof contained<" << typeid(T[N]).name() << ">::const_get is: " << typeid(&contained<T[N]>::const_get).name() << endl;
cout << "typeof contained<" << typeid(T[N]).name() << ">::call is: " << typeid(&contained<T[N]>::call).name() << endl;
cout << endl;
}
};
#endif
//
// check_wrap:
template <class T, class U>
void check_wrap(const contained<T>& w, const U& u)
{
cout << "checking contained<" << typeid(T).name() << ">..." << endl;
assert(w.value() == u);
}
//
// check_make_pair:
// verifies behaviour of "make_pair":
//
template <class T, class U, class V>
void check_make_pair(T c, U u, V v)
{
cout << "checking std::pair<" << typeid(c.first).name() << ", " << typeid(c.second).name() << ">..." << endl;
assert(c.first == u);
assert(c.second == v);
cout << endl;
}
struct UDT
{
int i_;
UDT() : i_(2){}
bool operator == (const UDT& v){ return v.i_ == i_; }
};
int main()
{
checker<UDT> c1;
UDT u;
c1(u);
checker<int> c2;
int i = 2;
c2(i);
int* pi = &i;
#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES)
checker<int*> c3;
c3(pi);
checker<int&> c4;
c4(i);
checker<const int&> c5;
c5(i);
#if !defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
int a[2] = {1,2};
checker<int[2]> c6;
c6(a);
#endif
#endif
check_wrap(wrap(2), 2);
const char ca[4] = "abc";
// compiler can't deduce this for some reason:
//check_wrap(wrap(ca), ca);
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
check_wrap(wrap(a), a);
check_make_pair(test::make_pair(a, a), a, a);
#endif
// cv-qualifiers applied to reference types should have no effect
// declare these here for later use with is_reference and remove_reference:
typedef int& r_type;
typedef const r_type cr_type;
type_test(UDT, boost::call_traits<UDT>::value_type)
type_test(UDT&, boost::call_traits<UDT>::reference)
type_test(const UDT&, boost::call_traits<UDT>::const_reference)
type_test(const UDT&, boost::call_traits<UDT>::param_type)
type_test(int, boost::call_traits<int>::value_type)
type_test(int&, boost::call_traits<int>::reference)
type_test(const int&, boost::call_traits<int>::const_reference)
type_test(const int, boost::call_traits<int>::param_type)
type_test(int*, boost::call_traits<int*>::value_type)
type_test(int*&, boost::call_traits<int*>::reference)
type_test(int*const&, boost::call_traits<int*>::const_reference)
type_test(int*const, boost::call_traits<int*>::param_type)
#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES)
type_test(int&, boost::call_traits<int&>::value_type)
type_test(int&, boost::call_traits<int&>::reference)
type_test(const int&, boost::call_traits<int&>::const_reference)
type_test(int&, boost::call_traits<int&>::param_type)
#if !(defined(__GNUC__) && (__GNUC__ < 3))
type_test(int&, boost::call_traits<cr_type>::value_type)
type_test(int&, boost::call_traits<cr_type>::reference)
type_test(const int&, boost::call_traits<cr_type>::const_reference)
type_test(int&, boost::call_traits<cr_type>::param_type)
#else
std::cout << "Your compiler cannot instantiate call_traits<int&const>, skipping four tests (4 errors)" << std::endl;
failures += 4;
test_count += 4;
#endif
type_test(const int&, boost::call_traits<const int&>::value_type)
type_test(const int&, boost::call_traits<const int&>::reference)
type_test(const int&, boost::call_traits<const int&>::const_reference)
type_test(const int&, boost::call_traits<const int&>::param_type)
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
type_test(const int*, boost::call_traits<int[3]>::value_type)
type_test(int(&)[3], boost::call_traits<int[3]>::reference)
type_test(const int(&)[3], boost::call_traits<int[3]>::const_reference)
type_test(const int*const, boost::call_traits<int[3]>::param_type)
type_test(const int*, boost::call_traits<const int[3]>::value_type)
type_test(const int(&)[3], boost::call_traits<const int[3]>::reference)
type_test(const int(&)[3], boost::call_traits<const int[3]>::const_reference)
type_test(const int*const, boost::call_traits<const int[3]>::param_type)
#else
std::cout << "You're compiler does not support partial template instantiation, skipping 8 tests (8 errors)" << std::endl;
failures += 8;
test_count += 8;
#endif
#else
std::cout << "You're compiler does not support partial template instantiation, skipping 20 tests (20 errors)" << std::endl;
failures += 20;
test_count += 20;
#endif
std::cout << std::endl << test_count << " tests completed (" << failures << " failures)... press any key to exit";
std::cin.get();
return failures;
}
//
// define call_traits tests to check that the assertions in the docs do actually work
// this is an instantiate only set of tests:
//
template <typename T, bool isarray = false>
struct call_traits_test
{
typedef ::boost::call_traits<T> ct;
typedef typename ct::param_type param_type;
typedef typename ct::reference reference;
typedef typename ct::const_reference const_reference;
typedef typename ct::value_type value_type;
static void assert_construct(param_type val);
};
template <typename T, bool isarray>
void call_traits_test<T, isarray>::assert_construct(typename call_traits_test<T, isarray>::param_type val)
{
//
// this is to check that the call_traits assertions are valid:
T t(val);
value_type v(t);
reference r(t);
const_reference cr(t);
param_type p(t);
value_type v2(v);
value_type v3(r);
value_type v4(p);
reference r2(v);
reference r3(r);
const_reference cr2(v);
const_reference cr3(r);
const_reference cr4(cr);
const_reference cr5(p);
param_type p2(v);
param_type p3(r);
param_type p4(p);
}
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
template <typename T>
struct call_traits_test<T, true>
{
typedef ::boost::call_traits<T> ct;
typedef typename ct::param_type param_type;
typedef typename ct::reference reference;
typedef typename ct::const_reference const_reference;
typedef typename ct::value_type value_type;
static void assert_construct(param_type val);
};
template <typename T>
void call_traits_test<T, true>::assert_construct(typename boost::call_traits<T>::param_type val)
{
//
// this is to check that the call_traits assertions are valid:
T t;
value_type v(t);
value_type v5(val);
reference r = t;
const_reference cr = t;
reference r2 = r;
#ifndef __BORLANDC__
// C++ Builder buglet:
const_reference cr2 = r;
#endif
param_type p(t);
value_type v2(v);
const_reference cr3 = cr;
value_type v3(r);
value_type v4(p);
param_type p2(v);
param_type p3(r);
param_type p4(p);
}
#endif //BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
//
// now check call_traits assertions by instantiating call_traits_test:
template struct call_traits_test<int>;
template struct call_traits_test<const int>;
template struct call_traits_test<int*>;
#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES)
template struct call_traits_test<int&>;
template struct call_traits_test<const int&>;
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
template struct call_traits_test<int[2], true>;
#endif
#endif

325
counting_iterator.htm Normal file
View File

@@ -0,0 +1,325 @@
<html>
<head>
<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">
<title>Counting Iterator Adaptor Documentation</title>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)"
align="center" width="277" height="86">
<h1>Counting Iterator Adaptor</h1>
Defined in header
<a href="../../boost/counting_iterator.hpp">boost/counting_iterator.hpp</a>
<p>
How would you fill up a vector with the numbers zero
through one hundred using <a
href="http://www.sgi.com/tech/stl/copy.html"><tt>std::copy()</tt></a>? The
only iterator operation missing from builtin integer types is an
<tt>operator*()</tt> 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
type that is <tt>Incrementable</tt> (see type requirements <a href="#requirements">below</a>). The
following <b>pseudo-code</b> shows the general idea of how the
counting iterator is implemented.
</p>
<pre>
// inside a hypothetical counting_iterator class...
typedef Incrementable value_type;
value_type counting_iterator::operator*() const {
return this->base; // no dereference!
}
</pre>
All of the other operators of the counting iterator behave in the same
fashion as the <tt>Incrementable</tt> base type.
<h2>Synopsis</h2>
<pre>
namespace boost {
template &lt;class Incrementable&gt;
struct <a href="#counting_iterator_traits">counting_iterator_traits</a>;
template &lt;class Incrementable&gt;
struct <a href="#counting_iterator_generator">counting_iterator_generator</a>;
template &lt;class Incrementable&gt;
typename counting_iterator_generator&lt;Incrementable&gt;::type
<a href="#make_counting_iterator">make_counting_iterator</a>(Incrementable x);
}
</pre>
<hr>
<h2><a name="counting_iterator_generator">The Counting Iterator Type
Generator</a></h2>
The class template <tt>counting_iterator_generator&lt;Incrementable&gt;</tt> is a <a href="../../more/generic_programming.html#type_generator">type generator</a> for counting iterators.
<pre>
template &lt;class Incrementable&gt;
class counting_iterator_generator
{
public:
typedef <a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a>&lt;...&gt; type;
};
</pre>
<h3>Example</h3>
In this example we use the counting iterator generator to create a
counting iterator, and count from zero to four.
<pre>
#include &lt;boost/config.hpp&gt;
#include &lt;iostream&gt;
#include &lt;boost/counting_iterator.hpp&gt;
int main(int, char*[])
{
// Example of using counting_iterator_generator
std::cout &lt;&lt; "counting from 0 to 4:" &lt;&lt; std::endl;
boost::counting_iterator_generator&lt;int&gt;::type first(0), last(4);
std::copy(first, last, std::ostream_iterator&lt;int&gt;(std::cout, " "));
std::cout &lt;&lt; std::endl;
// to be continued...
</pre>
The output from this part is:
<pre>
counting from 0 to 4:
0 1 2 3
</pre>
<h3>Template Parameters</h3>
<Table border>
<TR>
<TH>Parameter</TH><TH>Description</TH>
</TR>
<TR>
<TD><tt>Incrementable</tt></TD>
<TD>The type being wrapped by the adaptor.</TD>
</TR>
</Table>
<h3>Model of</h3>
If the <tt>Incrementable</tt> type has all of the functionality of a
<a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
Access Iterator</a> except the <tt>operator*()</tt>, then the counting
iterator will be a model of <a
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
Access Iterator</a>. If the <tt>Incrementable</tt> type has less
functionality, then the counting iterator will have correspondingly
less functionality.
<h3><a name="requirements">Type Requirements</a></h3>
The <tt>Incrementable</tt> type must be <a
href="http://www.sgi.com/tech/stl/DefaultConstructible.html">Default
Constructible</a>, <a href="./CopyConstructible.html">Copy
Constructible</a>, and <a href="./Assignable.html">Assignable</a>.
Also, the <tt>Incrementable</tt> type must provide access to an
associated <tt>difference_type</tt> and <tt>iterator_category</tt>
through the <a
href="#counting_iterator_traits"><tt>counting_iterator_traits</tt></a>
class.
<p>
Furthermore, if you wish to create a counting iterator that is a <a
href="http://www.sgi.com/tech/stl/ForwardIterator.html"> Forward
Iterator</a>, then the following expressions must be valid:
<pre>
Incrementable i, j;
++i // pre-increment
i == j // operator equal
</pre>
If you wish to create a counting iterator that is a <a
href="http://www.sgi.com/tech/stl/BidirectionalIterator.html">
Bidirectional Iterator</a>, then pre-decrement is also required:
<pre>
--i
</pre>
If you wish to create a counting iterator that is a <a
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html"> Random
Access Iterator</a>, then these additional expressions are also required:
<pre>
<a href="#counting_iterator_traits">counting_iterator_traits</a>&lt;Incrementable&gt;::difference_type n;
i += n
n = i - j
i < j
</pre>
<h3>Members</h3>
The counting iterator type implements the member functions and
operators required of the <a
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
Access Iterator</a> concept. In addition it has the following
constructor:
<pre>
counting_iterator_generator::type(const Incrementable&amp; i)
</pre>
<p>
<hr>
<p>
<h2><a name="make_counting_iterator">The Counting Iterator Object Generator</a></h2>
<pre>
template &lt;class Incrementable&gt;
typename counting_iterator_generator&lt;Incrementable&gt;::type
make_counting_iterator(Incrementable base);
</pre>
An <a href="../../more/generic_programming.html#object_generator">object
generator</a> function that provides a convenient way to create counting
iterators.<p>
<h3>Example</h3>
In this example we count from negative five to positive five, this
time using the <tt>make_counting_iterator()</tt> function to save some
typing.
<pre>
// continuing from previous example...
std::cout &lt;&lt; "counting from -5 to 4:" &lt;&lt; std::endl;
std::copy(boost::make_counting_iterator(-5),
boost::make_counting_iterator(5),
std::ostream_iterator&lt;int&gt;(std::cout, " "));
std::cout &lt;&lt; std::endl;
// to be continued...
</pre>
The output from this part is:
<pre>
counting from -5 to 4:
-5 -4 -3 -2 -1 0 1 2 3 4
</pre>
In the next example we create an array of numbers, and then create a
second array of pointers, where each pointer is the address of a
number in the first array. The counting iterator makes it easy to do
this since dereferencing a counting iterator that is wrapping an
iterator over the array of numbers just returns a pointer to the
current location in the array. We then use the <a
href="./indirect_iterator.htm">indirect iterator adaptor</a> to print
out the number in the array by accessing the numbers through the array
of pointers.
<pre>
// continuing from previous example...
const int N = 7;
std::vector&lt;int&gt; numbers;
// Fill "numbers" array with [0,N)
std::copy(boost::make_counting_iterator(0), boost::make_counting_iterator(N),
std::back_inserter(numbers));
std::vector&lt;std::vector&lt;int&gt;::iterator&gt; pointers;
// Use counting iterator to fill in the array of pointers.
std::copy(boost::make_counting_iterator(numbers.begin()),
boost::make_counting_iterator(numbers.end()),
std::back_inserter(pointers));
// Use indirect iterator to print out numbers by accessing
// them through the array of pointers.
std::cout &lt;&lt; "indirectly printing out the numbers from 0 to "
&lt;&lt; N &lt;&lt; std::endl;
std::copy(boost::make_indirect_iterator(pointers.begin()),
boost::make_indirect_iterator(pointers.end()),
std::ostream_iterator&lt;int&gt;(std::cout, " "));
std::cout &lt;&lt; std::endl;
</pre>
The output is:
<pre>
indirectly printing out the numbers from 0 to 7
0 1 2 3 4 5 6
</pre>
<hr>
<h2><a name="counting_iterator_traits">Counting Iterator Traits</a></h2>
The counting iterator adaptor needs to determine the appropriate
<tt>difference_type</tt> and <tt>iterator_category</tt> to use based on the
<tt>Incrementable</tt> type supplied by the user. The
<tt>counting_iterator_traits</tt> class provides these types. If the
<tt>Incrementable</tt> type is an integral type or an iterator, these types
will be correctly deduced by the <tt>counting_iterator_traits</tt> provided by
the library. Otherwise, the user must specialize
<tt>counting_iterator_traits</tt> for her type or add nested typedefs to
her type to fulfill the needs of
<a href="http://www.sgi.com/tech/stl/iterator_traits.html">
<tt>std::iterator_traits</tt></a>.
<p>The following pseudocode describes how the <tt>counting_iterator_traits</tt> are determined:
<pre>
template &lt;class Incrementable&gt;
struct counting_iterator_traits
{
if (numeric_limits&lt;Incrementable&gt::is_specialized) {
if (!numeric_limits&lt;Incrementable&gt::is_integer)
COMPILE_TIME_ERROR;
if (!numeric_limits&lt;Incrementable&gt::is_bounded
&amp;&amp; numeric_limits&lt;Incrementable&gt;::is_signed) {
typedef Incrementable difference_type;
}
else if (numeric_limits&lt;Incrementable&gt::is_integral) {
typedef <i>next-larger-signed-type-or-intmax_t</i> difference_type;
}
typedef std::random_access_iterator_tag iterator_category;
} else {
typedef std::iterator_traits&lt;Incrementable&gt;::difference_type difference_type;
typedef std::iterator_traits&lt;Incrementable&gt;::iterator_category iterator_category;
}
};
</pre>
<p>The italicized sections above are implementation details, but it is important
to know that the <tt>difference_type</tt> for integral types is selected so that
it can always represent the difference between two values if such a built-in
integer exists. On platforms with a working <tt>std::numeric_limits</tt>
implementation, the <tt>difference_type</tt> for any variable-length signed
integer type <tt>T</tt> is <tt>T</tt> itself.
<hr>
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->26 Feb 2001<!--webbot bot="Timestamp" endspan i-checksum="14386" --></p>
<p><EFBFBD> Copyright Jeremy Siek 2000. Permission to copy, use,
modify, sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided &quot;as is&quot;
without express or implied warranty, and with no claim as to its suitability for
any purpose.</p>
</body>
</html>
<!-- LocalWords: html charset alt gif hpp incrementable const namespace htm
-->
<!-- LocalWords: struct typename iostream int Siek CopyConstructible pre
-->

819
iterator_adaptors.htm Normal file
View File

@@ -0,0 +1,819 @@
<html>
<head>
<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">
<title>Header boost/iterator_adaptors.hpp Documentation</title>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)"
align="center" width="277" height="86">
<h1>Header
<a href="../../boost/pending/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a>
and
<a href="../../boost/pending/integer_range.hpp">boost/integer_range.hpp</a></h1>
<p>The file <tt>boost/iterator_adaptors.hpp</tt>
includes the main <tt>iterator_adaptors</tt> class and several other classes
for constructing commonly used iterator adaptors.</p>
<ul>
<li><a href="#iterator_adaptors"><tt>iterator_adaptors</tt></a>.
<li><a href="#iterator_adaptor"><tt>iterator_adaptor</tt></a>.
<li><a href="#transform_iterator"><tt>transform_iterator</tt></a>
<li><a href="#indirect_iterators"><tt>Indirect Iterator Adaptors</tt></a>
<li><a href="#projection_iterators"><tt>Projection Iterator Adaptors</tt></a>
<li><a href="#reverse_iterators"><tt>reverse_iterators</tt></a>
</ul>
<p>The file <tt>boost/integer_range.hpp</tt> includes a class that
uses iterator adaptors to create an iterator that increments over a
range of integers. The file also includes a &quot;container&quot; type
that creates a container-interface for the range of integers.
<ul>
<li><a href="#integer_range"><tt>integer_range</tt></a>
</ul>
<!-- put in something about Andrei Alexandrescu's contribution? -->
<p><a href="http://www.boost.org/people/dave_abrahams.htm">Dave
Abrahams</a> started the library, coming up with the idea to use
policy classes and how to handle the const/non-const iterator
interactions. He also contributed the <tt>indirect_iterators</tt> and
<tt>reverse_iterators</tt> classes.<br>
<a href="http://www.boost.org/people/jeremy_siek.htm">Jeremy Siek</a>
contributed <tt>transform_iterator</tt>, <tt>integer_range</tt>,
and this documentation.<br>
<a href="http://www.boost.org/people/john_potter.htm">John Potter</a>
contributed <tt>indirect_iterator</tt> and <tt>projection_iterator</tt>
and made some simplifications to <tt>iterator_adaptor</tt>.
<h3><a name="iterator_adaptors">The Iterator Adaptors Class</a></h3>
Implementing standard conforming iterators is a non-trivial task.
There are some fine-points such as iterator/const_iterator
interactions and there are the myriad of operators that should be
implemented but are easily forgotten such as
<tt>operator-&gt;()</tt>. The purpose of the
<tt>iterator_adaptors</tt> class is to make it easier to implement an
iterator class, and even easier to extend and adapt existing iterator
types. The <tt>iterator_adaptors</tt> class itself is not an adaptor
class but a <i>type generator</i>. It generates a pair of adaptor classes,
one class for the mutable iterator and one class for the const
iterator. The definition of the <tt>iterator_adaptors</tt> class is as
follows:
<p>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
<PRE>
template &lt;class Iterator,
class ConstIterator,
class Traits = std::iterator_traits&lt;Iterator&gt;,
class ConstTraits = std::iterator_traits&lt;ConstIterator&gt;,
class Policies = default_iterator_policies&gt;
struct iterator_adaptors
{
typedef ... iterator;
typedef ... const_iterator;
};
</PRE></TD></TABLE>
<p>The <tt>Iterator</tt> and <tt>ConstIterator</tt> template parameters
are the iterator types that you want to adapt. The <tt>Traits</tt> and
<tt>ConstTraits</tt> must be iterator traits classes. The traits
parameters default to the specialization of the
<tt>std::iterator_traits</tt> class for the adapted iterators. If you
want the traits for your new iterator adaptor (<tt>value_type</tt>,
<tt>iterator_category</tt>, etc.) to be the same as the adapted
iterator then use the default, otherwise create your own traits
classes and pass them in <a href="#1">[1]</a>.
<p>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
behaviours. You should also look at <tt>default_iterator_policies</tt>
as the &quot;boiler-plate&quot; for your own policy classes. The
following is definition of the <tt>default_iterator_policies</tt>
class:
<p>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
<PRE>
struct default_iterator_policies
{
// required for a ForwardIterator
template &lt;class Reference, class Iterator&gt;
Reference dereference(type&lt;Reference&gt;, const Iterator& x) const
{ return *x; }
template &lt;class Iterator&gt;
static void increment(Iterator& x)
{ ++x; }
template &lt;class Iterator1, class Iterator2&gt;
bool equal(Iterator1& x, Iterator2& y) const
{ return x == y; }
// required for a BidirectionalIterator
template &lt;class Iterator&gt;
static void decrement(Iterator& x)
{ --x; }
// required for a RandomAccessIterator
template &lt;class Iterator, class DifferenceType&gt;
static void advance(Iterator& x, DifferenceType n)
{ x += n; }
template &lt;class Difference, class Iterator1, class Iterator2&gt;
Difference distance(type&lt;Difference&gt;, Iterator1& x, Iterator2& y) const
{ return y - x; }
template &lt;class Iterator1, class Iterator2&gt;
bool less(Iterator1& x, Iterator2& y) const
{ return x &lt; y; }
};
</PRE></TD></TABLE>
<p>
The generated iterator adaptor types will have the following
constructors.
<p>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
<PRE>
<i>iterator</i>(const Iterator& i, const Policies& p = Policies())
<i>const_iterator</i>(const ConstIterator& i, const Policies& p = Policies())
</PRE></TD></TABLE>
<h3><a name="iterator_adaptor">The Iterator Adaptor Class</a></h3>
This is the class used inside of the <tt>iterator_adaptors</tt> type
generator. Use this class directly (instead of using
<tt>iterator_adaptors</tt>) when you are interested in creating only
one of the iterator types (either const or non-const) or when there is
no difference between the const and non-const versions of the iterator
type (often this is because there is only a const (read-only) version
of the iterator, as is the case for <tt>std::set</tt>'s iterators).
<p>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
<PRE>
template &lt;class Iterator,
class Policies = default_iterator_policies,
class Traits = std::iterator_traits&lt;Iterator&gt; &gt;
struct iterator_adaptor;
</PRE></TD></TABLE>
<p>
Next we will look at some iterator adaptors that are examples of how
to use the iterator adaptors class, and that are useful iterator
adaptors in their own right.
<h3><a name="transform_iterator">The Transform Iterator Class</a></h3>
It is often useful to automatically apply some function to the value
returned by dereferencing (<tt>operator*()</tt>) an iterator. The
<tt>transform_iterators</tt> class makes it easy to create an iterator
adaptor that does just that.
First let us consider what the <tt>Policies</tt> class for the transform
iterator should look like. We are only changing one of the iterator
behaviours, so we will inherit from
<tt>default_iterator_policies</tt>. In addition, we will need a
function object to apply, so we will have a template parameter and a
data member for the function object. The function will take one
argument (the dereferenced value) 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 corrent concept to choose for the
function object type. Now for the heart of our iterator adaptor, we
implement the <tt>dereference</tt> method, applying the function
object to <tt>*i</tt>. The <tt>type&lt;Reference&gt;</tt> class is
there to tell you what the reference type of the iterator is, which is
handy when writing generic iterator adaptors such as this one <a
href="#2">[2]</a>.
<p>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
<PRE>
template &lt;class AdaptableUnaryFunction&gt;
struct transform_iterator_policies : public default_iterator_policies
{
transform_iterator_policies() { }
transform_iterator_policies(const AdaptableUnaryFunction& f) : m_f(f) { }
template &lt;class Reference, class Iterator&gt;
Reference dereference(type&lt;Reference&gt;, const Iterator& i) const
{ return m_f(*i); }
AdaptableUnaryFunction m_f;
};
</PRE></TD></TABLE>
Next we need to create the traits class for our new iterator. In some
situations you may need to create a separate traits class for the
const and non-const iterator types, but here a single traits class
will do. The <tt>value_type</tt> and <tt>reference</tt> type of our
transform iterator will be the <tt>result_type</tt> of the function
object. The <tt>difference_type</tt> and <tt>iterator_category</tt>
will be the same as the adapted iterator.
<p>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
<PRE>
template &lt;class AdaptableUnaryFunction, class IteratorTraits&gt;
struct transform_iterator_traits {
typedef typename AdaptableUnaryFunction::result_type value_type;
typedef value_type reference;
typedef value_type* pointer;
typedef typename IteratorTraits::difference_type difference_type;
typedef typename IteratorTraits::iterator_category iterator_category;
};
</PRE></TD></TABLE>
The final step is to use the <tt>iterator_adaptor</tt> class to
construct our transform iterator. We will use the single iterator
adaptor version because we will not need to create both a mutable and
const version of the transform iterator. The transform iterator is
inherently a read-only iterator. The nicest way to package up our new
transform iterator is to create a type generator similar to
<tt>iterator_adaptor</tt>. The first template parameter will be the
type of the function object. The second parameter will be the adapted
iterator type. The third parameter is the trait class for
the adapted iterator. Inside the <tt>transform_iterators</tt> class
we use the <tt>transform_iterator_traits</tt> class defined above to
create the traits class for the new transform iterator. We then use
the <tt>iterator_adaptor</tt> class to extract the generated
iterator adaptor type.
<p>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
<PRE>
template &lt;class AdaptableUnaryFunction,
class Iterator,
class Traits = std::iterator_traits&lt;Iterator&gt;
&gt;
struct transform_iterator
{
typedef transform_iterator_traits&lt;AdaptableUnaryFunction,Traits&gt;
TransTraits;
typedef iterator_adaptor&lt;Iterator, TransTraits,
transform_iterator_policies&lt;AdaptableUnaryFunction&gt; &gt;::type type;
};
</PRE></TD></TABLE>
<p>
The following is a simple example of how to use the
<tt>transform_iterators</tt> class to iterate through a range of
numbers, multiplying each of them by 2 when they are dereferenced.
<p>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
<PRE>
#include &lt;functional&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 };
typedef std::binder1st&lt; std::multiplies&lt;int&gt; &gt; Function;
typedef boost::transform_iterator&lt;Function, int*,
boost::iterator&lt;std::random_access_iterator_tag, int&gt;
&gt;::type doubling_iterator;
doubling_iterator i(x, std::bind1st(std::multiplies&lt;int&gt;(), 2)),
i_end(x + sizeof(x)/sizeof(int), std::bind1st(std::multiplies&lt;int&gt;(), 2));
std::cout &lt;&lt; "multiplying the array by 2:" &lt;&lt; std::endl;
while (i != i_end)
std::cout &lt;&lt; *i++ &lt;&lt; " ";
std::cout &lt;&lt; std::endl;
return 0;
}
</PRE></TD></TABLE>
<h3><a name="indirect_iterators">The Indirect Iterator Adaptors</a></h3>
It is not all that uncommon to create data structures that consist of
pointers to pointers. For such a structure it might be nice to have an
iterator that applies a double-dereference inside the
<tt>operator*()</tt>. The implementation of this is similar to the
<tt>transform_iterators</tt><a href="#3">[3]</a>. When talking about a
data structure of pointers to pointers (or more generally, iterators
to iterators), we call the first level iterators the <i>outer</i>
iterators and the second level iterators the <i>inner</i>
iterators. For example, if the outer iterator type is <tt>T**</tt>
then the inner iterator type is <tt>T*</tt>.
To implement the indirect adaptors, we first create a policies class
which does a double-dereference in the <tt>dereference()</tt> method.
<p>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
<PRE>
struct indirect_iterator_policies : public default_iterator_policies
{
template &lt;class Reference, class Iterator&gt;
Reference dereference(type&lt;Reference&gt;, const Iterator& x) const
{ return **x; }
};
</PRE></TD></TABLE>
We then create a traits class, including a template parameter for both
the inner and outer iterators and traits classes. The
<tt>difference_type</tt> and <tt>iterator_category</tt> come from the
outer iterator, while the <tt>value_type</tt>, <tt>pointer</tt>, and
<tt>reference</tt> types come from the inner iterator.
<p>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
<PRE>
template &lt;class OuterIterator, class InnerIterator,
class OuterTraits = std::iterator_traits&lt;OuterIterator&gt;,
class InnerTraits = std::iterator_traits&lt;InnerIterator&gt;
&gt;
struct indirect_traits
{
typedef typename OuterTraits::difference_type difference_type;
typedef typename InnerTraits::value_type value_type;
typedef typename InnerTraits::pointer pointer;
typedef typename InnerTraits::reference reference;
typedef typename OuterTraits::iterator_category iterator_category;
};
</PRE></TD></TABLE>
Lastly we wrap this up in two type generators:
<tt>indirect_iterator</tt> for creating a single indirect iterator
type, and <tt>indirect_iterators</tt> for creating an const/non-const
pair of indirect iterator types. We use the <tt>iterator_adaptor</tt>
and <tt>iterator_adaptors</tt> classes here to do most of the work.
<p>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
<PRE>
template &lt;class OuterIterator, class InnerIterator,
class OuterTraits = std::iterator_traits&lt;OuterIterator&gt;,
class InnerTraits = std::iterator_traits&lt;InnerIterator&gt;
&gt;
struct indirect_iterator
{
typedef iterator_adaptor&lt;OuterIterator,
indirect_iterator_policies,
indirect_traits&lt;OuterIterator, InnerIterator,
OuterTraits, InnerTraits&gt;
&gt; type;
};
template &lt;class OuterIterator, // Mutable or Immutable, does not matter
class InnerIterator, // Mutable
class ConstInnerIterator, // Immutable
class OuterTraits = std::iterator_traits&lt;OuterIterator&gt;,
class InnerTraits = std::iterator_traits&lt;InnerIterator&gt;,
class ConstInnerTraits = std::iterator_traits&lt;ConstInnerIterator&gt;
&gt;
struct indirect_iterators
{
typedef iterator_adaptors&lt;OuterIterator, OuterIterator,
indirect_traits&lt;OuterIterator, InnerIterator,
OuterTraits, InnerTraits&gt;,
indirect_traits&lt;OuterIterator, ConstInnerIterator,
OuterTraits, ConstInnerTraits&gt;,
indirect_iterator_policies
&gt; Adaptors;
typedef typename Adaptors::iterator iterator;
typedef typename Adaptors::const_iterator const_iterator;
};
</PRE></TD></TABLE>
<h3><a name="projection_iterators">The Projection Iterator Adaptors</a></h3>
The projection iterator adaptor is very similar to the transform
iterator, except for a subtle difference in the return type: the
tranform iterator returns the result of the unary function by value,
whereas the projection iterator returns the result by reference.
Therefore, these two adaptors cater to different kinds of unary
functions. Transform iterator caters to functions that create new
objects, whereas projection iterator caters to a function that somehow
obtains a reference to an object that already exists. An example of a
unary function that is suitable for use with the projection adaptor is
<tt>select1st_</tt>:
<p>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
<PRE>
template &lt;class Pair&gt;
struct select1st_
: public std::unary_function&lt;Pair, typename Pair::first_type&gt;
{
const typename Pair::first_type& operator()(const Pair& x) const {
return x.first;
}
typename Pair::first_type& operator()(Pair& x) const {
return x.first;
}
};
</PRE></TD></TABLE>
The implementation of projection iterator is as follows. First, the
policies class is the same as the transform iterator's policies class.
<p>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
<PRE>
template &lt;class AdaptableUnaryFunction&gt;
struct projection_iterator_policies : public default_iterator_policies
{
projection_iterator_policies() { }
projection_iterator_policies(const AdaptableUnaryFunction& f) : m_f(f) { }
template &lt;class Reference, class Iterator&gt;
Reference dereference (type&lt;Reference&gt;, Iterator const& iter) const {
return m_f(*iter);
}
AdaptableUnaryFunction m_f;
};
</PRE></TD></TABLE>
Next we have two traits classes. We use <tt>value_type&</tt> for the
reference type of the mutable projection iterator, and <tt>const
value_type&</tt> for the immutable projection iterator.
<p>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
<PRE>
template &lt;class AdaptableUnaryFunction, class Traits&gt;
struct projection_iterator_traits {
typedef typename AdaptableUnaryFunction::result_type value_type;
typedef value_type& reference;
typedef value_type* pointer;
typedef typename Traits::difference_type difference_type;
typedef typename Traits::iterator_category iterator_category;
};
template &lt;class AdaptableUnaryFunction, class Traits&gt;
struct const_projection_iterator_traits {
typedef typename AdaptableUnaryFunction::result_type value_type;
typedef value_type const& reference;
typedef value_type const* pointer;
typedef typename Traits::difference_type difference_type;
typedef typename Traits::iterator_category iterator_category;
};
</PRE></TD></TABLE>
And to finish up, we create three generator classes that
use <tt>iterator_adaptor</tt> to create the projection iterator
types. The class <tt>projection_iterator</tt> creates a mutable
projection iterator type. The class <tt>const_projection_iterator</tt>
creates an immutable projection iterator type, and
<tt>projection_iterators</tt> creates both mutable and immutable
projection iterator types.
<p>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
<PRE>
template &lt;class AdaptableUnaryFunction, class Iterator,
class Traits = std::iterator_traits&lt;Iterator&gt;
&gt;
struct projection_iterator {
typedef projection_iterator_traits&lt;AdaptableUnaryFunction, Traits&gt;
Projection_Traits;
typedef iterator_adaptor&lt;Iterator,
projection_iterator_policies&lt;AdaptableUnaryFunction&gt;,
Projection_Traits&gt; type;
};
template &lt;class AdaptableUnaryFunction, class Iterator,
class Traits = std::iterator_traits&lt;Iterator&gt;
&gt;
struct const_projection_iterator {
typedef const_projection_iterator_traits&lt;AdaptableUnaryFunction,
Traits&gt; Projection_Traits;
typedef iterator_adaptor&lt;Iterator,
projection_iterator_policies&lt;AdaptableUnaryFunction&gt;,
Projection_Traits&gt; type;
};
template &lt;class AdaptableUnaryFunction, class Iterator, class ConstIterator,
class Traits = std::iterator_traits&lt;Iterator&gt;,
class ConstTraits = std::iterator_traits&lt;ConstIterator&gt;
&gt;
struct projection_iterators {
typedef projection_iterator_traits&lt;AdaptableUnaryFunction, Traits&gt;
Projection_Traits;
typedef const_projection_iterator_traits&lt;AdaptableUnaryFunction,
ConstTraits&gt; Const_Projection_Traits;
typedef iterator_adaptors&lt;Iterator, ConstIterator,
Projection_Traits, Const_Projection_Traits,
projection_iterator_policies&lt;AdaptableUnaryFunction&gt; &gt; Adaptors;
typedef typename Adaptors::iterator iterator;
typedef typename Adaptors::const_iterator const_iterator;
};
</PRE></TD></TABLE>
<h3><a name="reverse_iterators">The Reverse Iterators Class</a></h3>
<p>
Yes, there is already a <tt>reverse_iterator</tt> adaptor class
defined in the C++ Standard, but using the <tt>iterator_adaptors</tt>
class we can re-implement this classic adaptor in a more succinct and
elegant fashion. Also, this makes for a good example of using
<tt>iterator_adaptors</tt> that is in familiar territory.
<p>
The first step is to create the <tt>Policies</tt> class. As in the
<tt>std::reverse_iterator</tt> class, we need to flip all the
operations of the iterator. Increment will become decrement, advancing
by <tt>n</tt> will become retreating by <tt>n</tt>, etc.
<p>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
<PRE>
struct reverse_iterator_policies
{
template &lt;class Reference, class Iterator&gt;
Reference dereference(type&lt;Reference&gt;, const Iterator& x) const
{ return *boost::prior(x); }
// this is equivalent to { Iterator tmp = x; return *--tmp; }
template &lt;class Iterator&gt;
void increment(Iterator& x) const
{ --x; }
template &lt;class Iterator&gt;
void decrement(Iterator& x) const
{ ++x; }
template &lt;class Iterator, class DifferenceType&gt;
void advance(Iterator& x, DifferenceType n) const
{ x -= n; }
template &lt;class Difference, class Iterator1, class Iterator2&gt;
Difference distance(type&lt;Difference&gt;, Iterator1& x, Iterator2& y) const
{ return x - y; }
template &lt;class Iterator1, class Iterator2&gt;
bool equal(Iterator1& x, Iterator2& y) const
{ return x == y; }
template &lt;class Iterator1, class Iterator2&gt;
bool less(Iterator1& x, Iterator2& y) const
{ return y &lt; x; }
};
</PRE></TD></TABLE>
Since the traits of the reverse iterator adaptor will be the same as
the adapted iterator's traits, we do not need to create new traits
classes as was the case for <tt>transform_iterator</tt>. We can skip to
the final stage of creating a type generator class for our reverse
iterators using the <tt>iterator_adaptor</tt> class.
<p>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
<PRE>
template &lt;class Iterator, class ConstIterator,
class Traits = std::iterator_traits&lt;Iterator&gt;,
class ConstTraits = std::iterator_traits&lt;ConstIterator&gt;
&gt;
struct reverse_iterators
{
typedef iterator_adaptors&lt;Iterator,ConstIterator,Traits,ConstTraits,
reverse_iterator_policies&gt; Adaptor;
typedef typename Adaptor::iterator iterator;
typedef typename Adaptor::const_iterator const_iterator;
};
</PRE></TD></TABLE>
A typical use of the <tt>reverse_iterators</tt> class is in
user-defined container types. You can use the
<tt>reverse_iterators</tt> class to generate the reverse iterators for
your container.
<p>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
<PRE>
class my_container {
...
typedef ... iterator;
typedef ... const_iterator;
typedef reverse_iterators&lt;iterator, const_iterator&gt; RevIters;
typedef typename RevIters::iterator reverse_iterator;
typedef typename RevIters::const_iterator const_reverse_iterator;
...
};
</PRE></TD></TABLE>
<h3><a name="integer_range">The Integer Range Class</a></h3>
The <tt>iterator_adaptors</tt> class can not only be used for adapting
iterators, but it can also be used to take a non-iterator type and use
it to build an iterator. An especially simple example of this is
turning an integer type into an iterator, a counting iterator. The
builtin integer types of C++ are almost iterators. They have
<tt>operator++()</tt>, <tt>operator--()</tt>, etc. The one operator
they are lacking is the <tt>operator*()</tt>, which we will want to
simply return the current value of the integer. The following few
lines of code implement the policy and traits class for the counting
iterator.
<p>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
<PRE>
template &lt;class IntegerType&gt;
struct counting_iterator_policies : public default_iterator_policies
{
IntegerType dereference(type&lt;IntegerType&gt;, const IntegerType& i) const
{ return i; }
};
template &lt;class IntegerType&gt;
struct counting_iterator_traits {
typedef IntegerType value_type;
typedef IntegerType reference;
typedef value_type* pointer;
typedef std::ptrdiff_t difference_type;
typedef std::random_access_iterator_tag iterator_category;
};
</PRE></TD></TABLE>
Typically we will want to count the integers in some range, so a nice
interface would be to have a fake container that represents the range
of integers. The following is the definition of such a class called
<tt>integer_range</tt>.
<p>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
<PRE>
template &lt;class IntegerType&gt;
struct integer_range {
typedef typename iterator_adaptor&lt;IntegerType,
counting_iterator_traits&lt;IntegerType&gt;,
counting_iterator_policies &gt;::type iterator;
typedef iterator const_iterator;
typedef IntegerType value_type;
typedef std::ptrdiff_t difference_type;
typedef IntegerType reference;
typedef IntegerType* pointer;
typedef IntegerType size_type;
integer_range(IntegerType start, IntegerType finish)
: m_start(start), m_finish(finish) { }
iterator begin() const { return iterator(m_start); }
iterator end() const { return iterator(m_finish); }
size_type size() const { return m_finish - m_start; }
bool empty() const { return m_finish == m_start; }
void swap(integer_range& x) {
std::swap(m_start, x.m_start);
std::swap(m_finish, x.m_finish);
}
protected:
IntegerType m_start, m_finish;
};
</PRE></TD></TABLE>
<p>
The following is an example of how to use the
<tt>integer_range</tt> class to count from 0 to 4.
<p>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
<PRE>
boost::integer_range&lt;int&gt; r(0,5);
cout &lt;&lt; "counting to from 0 to 4:" &lt;&lt; endl;
std::copy(r.begin(), r.end(), ostream_iterator&lt;int&gt;(cout, " "));
cout &lt;&lt; endl;
</PRE></TD></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 hence
does not have a working <tt>std::iterator_traits</tt> class, you will
not be able to use the defaults and will need to supply your own
<tt>Traits</tt> and <tt>ConstTraits</tt> classes.
<p>
<a name="2">[2]</a>
The reference type could also be obtained from
<tt>std::iterator_traits</tt>, but that is not portable on compilers
that do not support partial specialization.
<p>
<a name="3">[3]</a>
It would have been more elegant to implement <tt>indirect_iterators</tt>
using <tt>transform_iterators</tt>, but for subtle reasons that would require
the use of <tt>boost::remove_cv</tt> which is not portable.
<h3>Implementation Notes</h3>
The code is somewhat complicated because there are three iterator
adaptor class: <tt>forward_iterator_adaptor</tt>,
<tt>bidirectional_iterator_adaptor</tt>, and
<tt>random_access_iterator_adaptor</tt>. The alternative would be to
just have one iterator adaptor equivalent to the
<tt>random_access_iterator_adaptor</tt>. The reason for going with
the three adaptors is that according to 14.5.3p5 in the C++ Standard,
friend functions defined inside a template class body are instantiated
when the template class is instantiated. This means that if we only
used the one iterator adaptor, then if the adapted iterator did not
meet all of the requirements for a
<a href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
RandomAccessIterator</a> then a compiler error should occur. Many
current compilers in fact do not instantiate the friend functions
unless used, so we could get away with the one iterator adaptor in
most cases. However, out of respect for the standard this implementation
uses the three adaptors.
<hr>
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->27 Nov 2000<!--webbot bot="Timestamp" endspan i-checksum="15248" --></p>
<p><EFBFBD> Copyright Jeremy Siek 2000. Permission to copy, use,
modify, sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided &quot;as is&quot;
without express or implied warranty, and with no claim as to its suitability for
any purpose.</p>
</body>
</html>