forked from boostorg/utility
made some more progress, starting filling in stuff about the implementation
[SVN r10315]
This commit is contained in:
@ -81,7 +81,7 @@ it automates the error-prone and redundant parts of the implementation
|
||||
and greatly simplifies the creation of iterator types that are
|
||||
variations on other iterators (adapted iterators). The Iterator
|
||||
Adaptor Library employs template meta-programming and is an example of
|
||||
policy-based design. It uses an extremeley flexible implementation
|
||||
policy-based design. It uses an extremely flexible implementation
|
||||
pattern which can be easily adapted to generate new representatives of
|
||||
other abstract Concept families.
|
||||
|
||||
@ -98,30 +98,31 @@ Iterators play an important role in modern C++ programing. The
|
||||
iterator is the central abstraction of the algorithms of the Standard
|
||||
Library and creating new iterator types and adapting old ones are
|
||||
common tasks for C++ programmers. There are plenty of examples of
|
||||
custom-made iterators in the literature: the
|
||||
iterators in the literature: the
|
||||
\code{line\_iterator}~\cite{austern99:_gener_progr_stl},
|
||||
\code{Constant\_iterator}~\cite{koenig97:_rumin_cpp},
|
||||
\code{Constant\_iterator}~\cite{koenig97:_rumin_cpp},
|
||||
\code{std::istream\_iterator} and
|
||||
\code{std::ostream\_iterator}~\cite{iso98:_cpp_final_draft_standard}n to
|
||||
name a few.
|
||||
\code{std::ostream\_iterator}~\cite{iso98:_cpp_final_draft_standard}
|
||||
to name a few.
|
||||
|
||||
% right here you introduce the notion of iterator adaptor as a
|
||||
% byproduct of saying something else. Should say:
|
||||
|
||||
An iterator adaptor's job is to adapt some \code{Base} type, often
|
||||
itself an iterator, to produce a new adapted iterator that conforms to
|
||||
the Conceptual requirements of its iterator category.
|
||||
|
||||
In addition, large number of iterator adaptors are now in use:
|
||||
iterators that adapt some \code{Base} type, often itself an iterator,
|
||||
to produce a new adapted iterator that conforms to the Conceptual
|
||||
requirements of its iterator category.
|
||||
%
|
||||
% although this may not be the best place for it.
|
||||
% I'm not sure if I changed your meaning by striking ``Also'' below:
|
||||
|
||||
A growing number of generic iterator adaptors are available:
|
||||
%
|
||||
Examples of iterator adaptors include
|
||||
\code{std::reverse\_iterator}~\cite{iso98:_cpp_final_draft_standard},
|
||||
\code{Checked\_iter}~\cite{stroustrup00:_cpp_prog_lang}, iterators of
|
||||
the View Template Library~\cite{TMPW00:Weiser}, custom and smart
|
||||
iterators~\cite{becker98:_smart_iteraters,TMPW00:Baus}, compound
|
||||
iterators~\cite{alexandrescu98:_compound_iters}, and several iterators
|
||||
in the MTL~\cite{siek99:_scitools}.
|
||||
from the MTL~\cite{siek99:_scitools}.
|
||||
|
||||
For an iterator to be usable with the Standard algorithms (and other
|
||||
generic algorithms in third-party libraries), it must fulfill the
|
||||
@ -136,7 +137,7 @@ despite the fact that most iterators are conceptually simple.
|
||||
Perhaps the most obvious reason that implementing an iterator can
|
||||
be tedious is that there are lots of redundant operators. That is,
|
||||
there are many operators that can be trivially defined in terms of
|
||||
other operators. For example, the postfix \code{operator++(int)} is often best
|
||||
other operators. For example, the post-fix \code{operator++(int)} is often best
|
||||
implemented in terms of prefix \code{operator++()} as shown below.
|
||||
|
||||
{\footnotesize
|
||||
@ -183,42 +184,45 @@ the \code{indirect\_iterator} is a tedious job.
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
template <class Iterator> class indirect_iterator {
|
||||
template <class Base> class indirect_iterator {
|
||||
public:
|
||||
// Adapt the meaning of dereference
|
||||
reference operator*() const {
|
||||
return **iter; // dereference twice
|
||||
}
|
||||
pointer operator->() const {
|
||||
return &**iter; // dereference twice
|
||||
}
|
||||
// a ``redundant'' operator
|
||||
pointer operator->() const { return &*(*this); }
|
||||
// Delegating the implementation to the underlying iterator.
|
||||
indirect_iterator& operator++() { ++iter; return *this; }
|
||||
indirect_iterator& operator--() { --iter; return *this; }
|
||||
// delegate for all the other operators...
|
||||
private:
|
||||
Iterator iter;
|
||||
Base iter;
|
||||
};
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
% I think it would be better to use reverse_iterator as an example
|
||||
% here, because it delegates more types than indirect_iterator does.
|
||||
In addition, a standard-conforming iterator must either come with a
|
||||
specialization of \code{std::iterator\_traits<>} or it must define
|
||||
five nested types: \code{value\_type}, \code{reference},
|
||||
\code{pointer}, \code{difference\_type}, and
|
||||
\code{iterator\_category}. In the example above, the last two would be
|
||||
delegated to the \code{Base} iterator type. For many iterator
|
||||
adaptors, all five must be delegated.
|
||||
% But reverse_iterator doesn't delegate many operators... it changes
|
||||
% the meaning of all of them. I wonder if there's a good example
|
||||
% for both operators and typedefs.
|
||||
A standard-conforming iterator must either come with a specialization
|
||||
of \code{std::iterator\_\-traits<>} or it must define five nested
|
||||
types: \code{value\_\-type}, \code{reference}, \code{pointer},
|
||||
\code{difference\_\-type}, and \code{iterator\_\-category}. In the
|
||||
example above, the last two would be delegated to the \code{Base}
|
||||
iterator type. For many iterator adaptors, all five must be delegated.
|
||||
|
||||
\subsection{Iterator Complexities}
|
||||
|
||||
In addition to the tedious aspects of iterator implementation, there
|
||||
are some complexities that trip up even the most experienced of
|
||||
programmers.
|
||||
programmers. Ideally, an iterator implementer should not have to worry
|
||||
about these details.
|
||||
|
||||
\subsubsection{Constant/Mutable Iterator Interactions}
|
||||
\label{sec:constant-mutable-iterations}
|
||||
|
||||
Iterators over containers and other sequences of stored objects
|
||||
usually come in pairs: a constant iterator type and a mutable iterator
|
||||
@ -228,7 +232,7 @@ subtraction. For example, suppose
|
||||
that you are implementing a container type \code{C}. Then you ought to
|
||||
define the following four version of \code{operator==}, along with
|
||||
corresponding versions of \code{operator!=}, and (for
|
||||
RandomAccessIterators), operators \code{<}, \code{>},
|
||||
\stlconcept{RandomAccessIterator}), operators \code{<}, \code{>},
|
||||
\code{<=}, \code{>=}, and \code{-}.
|
||||
|
||||
|
||||
@ -248,24 +252,25 @@ example, a reverse iterator adaptor applied to \code{C::iterator} and
|
||||
\code{C::const\_iterator} should result in mutable and constant reverse iterator types that
|
||||
have the same ability to interact as the \code{Base} iterators do.
|
||||
|
||||
\subsubsection{Constant/Mutable Iterator Implementation}
|
||||
\subsubsection{Constant/Mutable Iterator Code Duplication}
|
||||
|
||||
% Is this section really worthwhile? It was confusing to read until I
|
||||
% finally figured out what you were driving at. Who makes this conceptual mistake?
|
||||
Another subtlety in the implementation of iterators is how the the
|
||||
distinction between constant and mutable iterators affects the
|
||||
implementation. It is obvious that a constant iterator should have
|
||||
\code{const} \code{reference} and \code{pointer} types, while a mutable iterator should have a
|
||||
non-\code{const} \code{reference} and \code{pointer}, though in other regards the constant and
|
||||
mutable versions of an iterator are the same. It is therefore
|
||||
desirable to implement both versions of the iterator with a the same
|
||||
code. It is possible to do this, however some care must be taken.
|
||||
% It may not be worthwhile... though I've seen other grad students make
|
||||
% this mistake, and the TMPW2000 VTL paper contains this mistake.
|
||||
|
||||
One common mistake is that the programmer will confuse the ideas of
|
||||
a \code{const} iterator object and a \emph{constant iterator}. Such a
|
||||
misunderstanding can, for example, lead to a single iterator class that has
|
||||
two versions of \code{operator*}, one that is a \code{const} member function
|
||||
and one that is not.
|
||||
The implementations of the constant and mutable versions of an
|
||||
iterator typically differ only in their \code{reference} and
|
||||
\code{pointer} types. Therefore it is desirable to merge the two
|
||||
iterator classes into a single class template with the
|
||||
\code{reference} and \code{pointer} types as template parameters.
|
||||
|
||||
Some care must be taken when merging the constant and mutable
|
||||
iterators. One common mistake is that the programmer will confuse the
|
||||
ideas of a \code{const} iterator object and a \emph{constant
|
||||
iterator}. Such a misunderstanding can, for example, lead to an
|
||||
iterator class template that has two versions of \code{operator*}, one
|
||||
that is a \code{const} member function and one that is not.
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
@ -275,11 +280,6 @@ and one that is not.
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
The right way to implement both a constant and mutable iterators using
|
||||
the same code is to use a class template parameterized on the
|
||||
\code{reference} type. To create the constant iterator a \code{const}
|
||||
reference would be used as the template argument and to create the
|
||||
mutable iterator a non-\code{const} reference would be used instead.
|
||||
There should be only one \code{operator*} that returns the
|
||||
\code{reference} type and the member function should be \code{const} since
|
||||
dereferencing an iterator does not change the state of the iterator
|
||||
@ -294,17 +294,410 @@ object itself (unlike \code{operator++}).
|
||||
|
||||
|
||||
\subsubsection{Input Iterators and \code{operator->}}
|
||||
\label{sec:operator-arrow}
|
||||
|
||||
When creating an iterator adaptor that produces an
|
||||
\stlconcept{InputIterator} some extra care must be
|
||||
taken in the implementation of \code{operator->}. Remember that an
|
||||
input iterator need not iterate over stored objects: it
|
||||
can manufacture new objects when it is dereferenced as is the case for
|
||||
\stlconcept{InputIterator} some extra care must be taken in the
|
||||
implementation of \code{operator->}. Remember that an input iterator
|
||||
need not iterate over stored objects: it can manufacture new objects
|
||||
when it is dereferenced as is the case for
|
||||
\code{std::istream\_iterator}. If the iterator's \code{value\_type} is
|
||||
of class type, we need to support \code{operator->}. Since the result
|
||||
of using \code{operator->} must produce a true pointer even when
|
||||
dereferencing the iterator does not yeild a true reference type, we
|
||||
need a \code{const} lvalue to which a pointer can be formed.
|
||||
dereferencing the iterator does not yield a true reference type, we
|
||||
need a \code{const} lvalue to which a pointer can be formed. In
|
||||
\S\ref{sec:operator-arrow} we show how this can be accomplished.
|
||||
|
||||
|
||||
\subsubsection{The Return Type of \code{operator[]} for Adaptors}
|
||||
\label{sec:operator-bracket}
|
||||
|
||||
The C++ Standard specifies that the return type of \code{operator[]}
|
||||
of a random access iterator must be ``convertible to \code{T}''. This
|
||||
is a rather lenient requirement since \code{operator*} is required to
|
||||
return the exact type \code{T\&}, and one might think that
|
||||
\code{operator[]} and \code{operator*} should be same in this respect.
|
||||
The C++ Standards Committee is currently debating as to whether the
|
||||
random access iterator requirements should be changed.
|
||||
|
||||
To complicate the matter, returning \code{T\&} from \code{operator[]}
|
||||
causes a run-time error in a certain class of situations. We will
|
||||
discuss this in detail in \S\ref{sec:op-bracket-impl}.
|
||||
|
||||
|
||||
% Automatic implementation of redundant operators
|
||||
% Default delegation to adapted iterator
|
||||
|
||||
% complexities:
|
||||
% const-non const interaction
|
||||
% const/mutable iterator distinction
|
||||
% input iterator \code{operator->}
|
||||
|
||||
\section{The Boost \code{iterator\_adaptor} Class Template}
|
||||
|
||||
The \code{iterator\_\-adaptor} class template simplifies the creation
|
||||
of iterators by automating the implementation of redundant operators
|
||||
and delegating functions and by taking care of the complex details of
|
||||
iterator implementation.
|
||||
|
||||
The central design feature of \code{iterator\_\-adaptor} is the
|
||||
parameterization by an iterator policies class. The policies class is
|
||||
the primary communication mechanism between the iterator implementer
|
||||
and the \code{iterator\_\-adaptor}; it specifies how the new iterator
|
||||
type is different from the \code{Base} type. Unlike the policy classes
|
||||
in~\cite{alexandrescu01:_modern_cpp_design}, we group several policies
|
||||
into a single class, as this proved more convenient for iterator
|
||||
implementation.
|
||||
|
||||
\subsection{Iterator Policies Class}
|
||||
|
||||
In the following we show an example of implementing the policies class
|
||||
for a transform iterator adaptor: an iterator that applies some
|
||||
function to the value returned by dereferencing the base iterator.
|
||||
The \code{transform\_\-iterator\_\-policies} class is templated on the
|
||||
function object type, and a function object is stored as a data member
|
||||
of the policies class. In general, any extra state needed by the
|
||||
iterator should be stored in the policies class. The policies class
|
||||
inherits from \code{default\_\-iterator\_\-policies}, which delegates
|
||||
all other operations to the base iterator. The main event of the
|
||||
\code{transform\_\-iterator\_\-policies} class is the
|
||||
\code{dereference()} member function, which simply applies the
|
||||
function to the dereferenced value. The base iterator object is the
|
||||
second argument to the \code{dereference()} function. The iterator
|
||||
type is a template parameter to allow this policy class to be used
|
||||
with any base iterator type.
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
template <class AdaptableUnaryFunction>
|
||||
struct transform_iterator_policies : public default_iterator_policies
|
||||
{
|
||||
transform_iterator_policies() { }
|
||||
transform_iterator_policies(const AdaptableUnaryFunction& f)
|
||||
: m_f(f) { }
|
||||
template <class Reference, class BaseIterator>
|
||||
Reference dereference(type<Reference>, const BaseIterator& i) const
|
||||
{ return m_f(*i); } // apply the function and return the result
|
||||
AdaptableUnaryFunction m_f;
|
||||
};
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
The \code{type<Reference>} parameter is used to convey the appropriate
|
||||
return type to the \code{dereference()} function. This method is
|
||||
perhaps not the most elegant, but it was the most portable solution.
|
||||
|
||||
A policies class is required to have a default constructor because the
|
||||
\code{iterator\_\-adaptor} has an instance of the policies class as a
|
||||
data-member, and iterators are required to have default constructors
|
||||
thereby requiring the policies class to also have a default
|
||||
constructor.
|
||||
|
||||
With the policies class complete, the iterator implementer is almost
|
||||
finished: and only eleven lines of code have been written. The code
|
||||
consists of little more than the main idea of the transform iterator,
|
||||
applying a function to the result of dereferencing the base iterator.
|
||||
Next we will take a closer look at the
|
||||
\code{default\_\-iterator\_\-policies} class and then in
|
||||
\S\ref{sec:iter-type-generator} we will show how the transform
|
||||
iterator type is constructed using \code{iterator\_\-adaptor}.
|
||||
|
||||
|
||||
\subsection{Default Iterator Policies Class}
|
||||
|
||||
The \code{default\_\-iterator\_\-policies} class is the mechanism that
|
||||
provides automatic delegation to the base iterator, freeing the
|
||||
iterator implementer from the tedious task of writing delegating
|
||||
functions. As above, an iterator policies class inherits from this
|
||||
class and overrides any functions that should not be delegated. The
|
||||
\code{default\_\-iterator\_\-policies} class also serves as an example
|
||||
of the iterator policies interface. There are seven member functions
|
||||
that correspond to the core iterator operations and an
|
||||
\code{initialize()} function to provide a hook for customization of
|
||||
iterator construction.
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
namespace boost {
|
||||
struct default_iterator_policies
|
||||
{
|
||||
template <class Base>
|
||||
void initialize(Base&) { }
|
||||
|
||||
template <class Reference, class Base>
|
||||
Reference dereference(type<Reference>, const Base& x) const
|
||||
{ return *x; }
|
||||
|
||||
template <class Base>
|
||||
void increment(Base& x) { ++x; }
|
||||
|
||||
template <class Base>
|
||||
void decrement(Base& x) { --x; }
|
||||
|
||||
template <class Base, class DifferenceType>
|
||||
void advance(Base& x, DifferenceType n) { x += n; }
|
||||
|
||||
template <class Difference, class Base1, class Base2>
|
||||
Difference distance(type<Difference>, const Base1& x,
|
||||
const Base2& y) const { return y - x; }
|
||||
|
||||
template <class Base1, class Base2>
|
||||
bool equal(const Base1& x, const Base2& y) const
|
||||
{ return x == y; }
|
||||
|
||||
template <class Base1, class Base2>
|
||||
bool less(const Base1& x, const Base2& y) const
|
||||
{ return x < y; }
|
||||
};
|
||||
} // namespace boost
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
|
||||
\subsection{Iterator Type Generator}
|
||||
\label{sec:iter-type-generator}
|
||||
|
||||
With the policy class for the transform iterator complete, the next
|
||||
step is to use the \code{iterator\_adaptor} template to construct the
|
||||
actual iterator type. The best way to package the construction of the
|
||||
transform iterator is to create a \emph{type generator}, which is a
|
||||
class template whose sole purpose is to simplify the instantiation of
|
||||
some other complicated class template. It fulfills the same need as a
|
||||
templated typedef would if that were part of the {C++} language.
|
||||
The following code shows the type generator for the transform
|
||||
iterator.
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
template <class AdaptableUnaryFunction, class Iterator>
|
||||
struct transform_iterator_generator
|
||||
{
|
||||
typedef typename AdaptableUnaryFunction::result_type value_type;
|
||||
public:
|
||||
typedef iterator_adaptor<Iterator,
|
||||
transform_iterator_policies<AdaptableUnaryFunction>,
|
||||
value_type, value_type, value_type*, std::input_iterator_tag> type;
|
||||
};
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
We use \code{iterator\_adaptor} to define the transform iterator type
|
||||
as a nested \code{typedef} inside the
|
||||
\code{transform\_iterator\_generator} class. The first template
|
||||
parameter to the generator is the type of the function object and the
|
||||
second is the base iterator type. The remaining types specify the
|
||||
traits of the iterator: \code{value\_type}, \code{reference},
|
||||
\code{pointer}, and \code{iterator\_\-category}. Because the function
|
||||
may return by-value, we must limit the \code{iterator\_category} to
|
||||
\code{std::input\_\-iterator\_\-tag}, and the iterator's
|
||||
\code{reference} type cannot be a true reference (the standard allows
|
||||
this for input iterators). The last template parameter of the
|
||||
\code{iterator\_adaptor} is for the \code{difference\_\-type}, which
|
||||
in this case will default to the \code{difference\_\-type} of the base
|
||||
iterator.
|
||||
|
||||
|
||||
\subsection{Iterator Object Generator}
|
||||
\label{sec:iter-object-generator}
|
||||
|
||||
The next question is how users of the transform iterator will
|
||||
construct the iterator. The \code{iterator\_\-adaptor} class has the
|
||||
following constructor.
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
explicit
|
||||
iterator_adaptor(const Base& it, const Policies& p = Policies())
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
It would be cumbersome for the user to call this constructor since
|
||||
they would have to separately construct a policies class object and
|
||||
then the iterator object. We therefore recommend that iterator
|
||||
implementers create an \emph{object generator} function for their
|
||||
iterator. The following is the generator function for the transform
|
||||
iterator adaptor.
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
template <class AdaptableUnaryFunction, class Iterator>
|
||||
typename transform_iterator_generator<AdaptableUnaryFunction,
|
||||
Iterator>::type
|
||||
make_transform_iterator(Iterator base,
|
||||
const AdaptableUnaryFunction& f = AdaptableUnaryFunction())
|
||||
{
|
||||
typedef typename transform_iterator_generator<AdaptableUnaryFunction,
|
||||
Iterator>::type result_t;
|
||||
transform_iterator_policies<AdaptableUnaryFunction> policies(f);
|
||||
return result_t(base, policies);
|
||||
}
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
An alternative solution to using object generating functions would be
|
||||
to have a constructor in \code{iterator\_adaptor} that takes arbitrary
|
||||
arguments (the constructor would be templated). The arguments would
|
||||
then be passed as a heterogeneous value list~\cite{TMPW00:Eisenecker}
|
||||
to the policies class. This would remove the need for object
|
||||
generating functions but would increase the complexity of the
|
||||
implementation and the compile time. For a low-level component such as
|
||||
an iterator adaptor we felt that simplicity and compile-time were more
|
||||
important than implementer convenience.
|
||||
|
||||
\subsection{Example Use of the Transform Iterator Adaptor}
|
||||
|
||||
The following example shows how a transform iterator can be used to
|
||||
iterate through a range of numbers, multiplying each of them by 2 and
|
||||
printing the result to standard output.
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||
const int N = sizeof(x)/sizeof(int);
|
||||
std::cout << "multiplying the array by 2:" << std::endl;
|
||||
std::copy(boost::make_transform_iterator(x,
|
||||
std::bind1st(std::multiplies<int>(), 2)),
|
||||
boost::make_transform_iterator(x + N,
|
||||
std::bind1st(std::multiplies<int>(), 2)),
|
||||
std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
return 0;
|
||||
}
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
\noindent This output is:
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
2 4 6 8 10 12 14 16
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
|
||||
\section{The Implementation of \code{iterator\_adaptor}}
|
||||
|
||||
The outline for the implementation of the \code{iterator\_adaptor}
|
||||
class is as follows. In the next few sections we will discuss aspects
|
||||
of the implementation in more depth, including how the problems
|
||||
discussed in the introduction were solved.
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
namespace boost {
|
||||
template <class Base, class Policies,
|
||||
class Value = default_argument,
|
||||
class Reference = default_argument,
|
||||
class Pointer = default_argument,
|
||||
class Category = default_argument,
|
||||
class Distance = default_argument>
|
||||
struct iterator_adaptor {
|
||||
// Deduce iterator associated types (value_type, etc.) from the
|
||||
// template parameters, and handle any named template parameters.
|
||||
public:
|
||||
// Core operators, delegate to policies class.
|
||||
// Redundant operators, implemented in terms of the core operators.
|
||||
private:
|
||||
compressed_pair<Base, Policies> m_iter_p;
|
||||
// If the policies class is empty, apply the empty-base class
|
||||
// optimization to conserve space. The base is ``first'' and
|
||||
// the policies are ``second''.
|
||||
Policies& policies() { return m_iter_p.second(); }
|
||||
Base& iter() { return m_iter_p.first(); }
|
||||
// and the same for const references...
|
||||
};
|
||||
// Core binary operators.
|
||||
// Redundant binary operators.
|
||||
} // namespace boost
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
\subsection{Deducing the Associates Types}
|
||||
|
||||
\subsubsection{Default Types}
|
||||
|
||||
\subsubsection{Named Template Parameters}
|
||||
|
||||
|
||||
\subsection{Core Operators}
|
||||
|
||||
The core operators of the \code{iterator\_adaptor} are implemented by
|
||||
delegating the work to the policies class. Each core operator invokes
|
||||
the appropriate policy function and passes in the base
|
||||
iterator. Sometimes extra type information is also passed in, as is
|
||||
the case with the \code{reference} type in the implementation of
|
||||
\code{operator*}.
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
reference operator*() const {
|
||||
return policies().dereference(type<reference>(), iter());
|
||||
}
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
The binary operators of the iterator are implemented as free functions
|
||||
(not member functions) to allow both the left and right hand operands
|
||||
to be treated symmetrically. We use separate template parameters for
|
||||
the two \code{iterator\_\-adaptor} arguments. This allows a single
|
||||
operator to implement all of the combinations of constant/mutable
|
||||
iterator interactions, avoiding the combinatorial explosion discussed
|
||||
in \S\ref{sec:constant-mutable-iterations}. Note that we only use a
|
||||
single \code{Policies} template parameter: this restricts iterator
|
||||
interaction to those iterators with the same policies class. This is
|
||||
not restrictive as it should be, however the only real disadvantage to
|
||||
not being restrictive enough is in the kind of error message the user
|
||||
will see when misusing two unrelated iterators. Instead of an
|
||||
``operator not found'' message they will see an error message from
|
||||
inside the iterator adaptor.
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
template <class Iter1, class Iter2, class Policies, class V1, class V2,
|
||||
class R1, class R2, class P1, class P2, class C1, class C2,
|
||||
class D1, class D2>
|
||||
bool operator<(
|
||||
const iterator_adaptor<Iter1,Policies,V1,R1,P1,C1,D1>& x,
|
||||
const iterator_adaptor<Iter2,Policies,V2,R2,P2,C2,D2>& y)
|
||||
{
|
||||
return x.policies().less(x.iter(), y.iter());
|
||||
}
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
|
||||
\subsection{Redundant Operators}
|
||||
|
||||
Most of the redundant operators are implemented in a straightforward
|
||||
way based on the core operators. For example, the \code{operator+} is
|
||||
implemented in terms of \code{operator+=}.
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
template <class B, class P, class V, class R, class Ptr,
|
||||
class C, class D, class Distance>
|
||||
iterator_adaptor<B,P,V,R,Ptr,C,D>
|
||||
operator+(iterator_adaptor<B,P,V,R,Ptr,C,D> p, Distance x)
|
||||
{
|
||||
return p += x;
|
||||
}
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
The implementation of \code{operator->} and \code{operator[]}, as
|
||||
alluded to in \S\ref{sec:operator-arrow} and
|
||||
\S\ref{sec:operator-bracket}, are not straightforward. We discuss them
|
||||
in the following two sections.
|
||||
|
||||
|
||||
\subsubsection{Implementing \code{operator->} for Input Iterators}
|
||||
\label{sec:operator-arrow}
|
||||
|
||||
Fortunately, the standard gives us a way: section 13.3.1.2 paragraph 8
|
||||
describes a seemingly quirky rule that the \code{->} operator will be
|
||||
@ -312,10 +705,10 @@ applied to the \emph{result} of any call to \code{operator->}. This is
|
||||
a convenient way to describe the semantics of ordinary
|
||||
\code{operator->}, which returns a pointer: it just uses the pointer
|
||||
to perform the usual member dereferencing. It also turns out to be
|
||||
what we need to make conforming \stlconcept{InputIterators}. By making
|
||||
the return type of \code{operator->} a proxy containing an instance of
|
||||
the iterator's \code{value\_type}, we can eventually form a
|
||||
\code{const} pointer to the returned temporary:
|
||||
what we need to make a conforming \stlconcept{InputIterator}. By
|
||||
making the return type of \code{operator->} a proxy containing an
|
||||
instance of the iterator's \code{value\_type}, we can eventually form
|
||||
a \code{const} pointer to the returned temporary:
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
@ -348,26 +741,24 @@ appropriate type for the result of an iterator's \code{operator->}:
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
The boost Type Traits library is used to check whether the iterator's
|
||||
The Boost Type Traits library is used to check whether the iterator's
|
||||
category is no more refined than \stlconcept{InputIterator}. If so,
|
||||
the appropriate \code{operator\_arrow\_proxy} is selected.
|
||||
Convertibility is used as a criterion to allow for user-defined
|
||||
iterator categories derived from the standard ones.
|
||||
|
||||
\subsubsection{The Return Type of \code{operator[]} for Adaptors}
|
||||
|
||||
The C++ Standard specifies that the return type of \code{operator[]}
|
||||
of a random access iterator must be ``convertible to \code{T}''. This
|
||||
is a rather lenient requirement since \code{operator*} is required to
|
||||
return the exact type \code{T\&}, and one might think that
|
||||
\code{operator[]} and \code{operator*} should be same in this respect.
|
||||
The C++ Standards Committee is currently debating as to whether the
|
||||
random access iterator requirements should be changed.
|
||||
\subsubsection{Implementation of \code{operator[]}}
|
||||
|
||||
To complicate the matter, returning \code{T\&} from \code{operator[]}
|
||||
causes a run-time error in a certain class of situations. Suppose the
|
||||
adapted iterator is reading in elements from a file and caching each
|
||||
element as a data member of the iterator.
|
||||
The implementation of \code{operator[]} would be trivial except for
|
||||
the issue surrounding what the return type should be. As discussed in
|
||||
\S\ref{sec:iterator-bracket}, it would be dangerous to make the
|
||||
\code{iterator\_adaptor} always return a reference for
|
||||
\code{operator[]} for there are certain situations in which this can
|
||||
cause run-time errors.
|
||||
|
||||
Suppose the adapted iterator is reading in elements from a file and
|
||||
caching each element as a data member of the iterator.
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
@ -406,156 +797,41 @@ dereference returns a reference to a data member of this
|
||||
temporary. The result is a dangling reference being returned from
|
||||
\code{operator[]}.
|
||||
|
||||
Under the current state of affairs returning by-value from the
|
||||
\code{operator[]} of an adaptor is the safer and therefore better
|
||||
approach. Ideally the return type of an iterator adaptor's
|
||||
\code{operator[]} would be varied depending on the characteristics of
|
||||
the underlying iterator, and there would be a standard iterator
|
||||
category for describing random access iterators that do not return
|
||||
lvalues such as proposed in~\cite{siek01:_improved_iter_cat}.
|
||||
|
||||
% Automatic implementation of redundant operators
|
||||
% Default delegation to adapted iterator
|
||||
|
||||
% complexities:
|
||||
% const-non const interaction
|
||||
% const/mutable iterator distinction
|
||||
% input iterator \code{operator->}
|
||||
|
||||
\section{The Boost \code{iterator\_adaptor}}
|
||||
|
||||
|
||||
|
||||
\subsection{Example}
|
||||
|
||||
It is often useful to automatically apply some function to the value
|
||||
returned by dereferencing an iterator. The transform iterator of the
|
||||
Iterator Adaptor Library makes it easy to create an iterator adaptor
|
||||
which does just that. Here we will show how easy it is to implement
|
||||
the transform iterator using the
|
||||
\code{iterator\_adaptor} template.
|
||||
|
||||
We want to be able to adapt a range of iterators and functions, so the
|
||||
policies class will have a template parameter for the function type
|
||||
and it will have a data member of that type. We know that the function
|
||||
takes one argument and that we'll need to be able to deduce the
|
||||
\code{result\_type} of the function so we can use it for the adapted
|
||||
iterator's \code{value\_type}. \stlconcept{AdaptableUnaryFunction} is
|
||||
the \textsf{concept}\cite{austern99:_gener_progr_stl} that fulfills
|
||||
those requirements.
|
||||
|
||||
To implement a transform iterator we will only change one of the base
|
||||
iterator's behaviors, so the \code{transform\_iterator\_policies}
|
||||
class can inherit the rest from \code{default\_iterator\_policies}. We
|
||||
will define the \code{dereference()} member function, which is used
|
||||
to implement \code{operator*()} of the adapted iterator. The
|
||||
implementation will dereference the base iterator and apply the
|
||||
function object. The \code{type<Reference>} parameter is used
|
||||
to convey the appropriate return type. The complete code for
|
||||
\code{transform\_iterator\_policies} is:
|
||||
The \code{iterator\_adaptor} takes the safe route and returns the
|
||||
result by-value. This meets the random access iterator requirements of
|
||||
the Standard, which only says that the return type must be
|
||||
``convertible to T'',
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
template <class AdaptableUnaryFunction>
|
||||
struct transform_iterator_policies : public default_iterator_policies
|
||||
{
|
||||
transform_iterator_policies() { }
|
||||
transform_iterator_policies(const AdaptableUnaryFunction& f)
|
||||
: m_f(f) { }
|
||||
template <class Reference, class BaseIterator>
|
||||
Reference dereference(type<Reference>, const BaseIterator& i) const
|
||||
{ return m_f(*i); }
|
||||
AdaptableUnaryFunction m_f;
|
||||
};
|
||||
value_type operator[](difference_type n) const
|
||||
{ return *(*this + n); }
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
The next step is to use the \code{iterator\_adaptor} template to
|
||||
construct the transform iterator type. The nicest way to package the
|
||||
construction of the transform iterator is to create a \emph{type
|
||||
generator}, which is a class template whose sole purpose is to
|
||||
simplify the instantiation of some other complicated class
|
||||
template. It fulfills the same need as a templated typedef would if
|
||||
that were part of the {C++} language.
|
||||
Under the current {C++} Standard, when using a random access iterator
|
||||
in a generic algorithm, you can not use \code{operator[]} for
|
||||
assignment (on the left hand side) but instead must write \code{*(i +
|
||||
n) = x}.
|
||||
|
||||
The first template parameter to the generator will be the type of the
|
||||
function object and the second will be the base iterator type. We use
|
||||
\code{iterator\_adaptor} to define the transform iterator type as a
|
||||
nested \code{typedef} inside the
|
||||
\code{transform\_iterator\_generator} class. Because the function may
|
||||
return by-value, we must limit the \code{iterator\_category} to
|
||||
\stlconcept{InputIterator}, and the iterator's \code{reference} type cannot be a
|
||||
true reference (the standard allows this for input iterators), so in
|
||||
this case we can use few of \code{iterator\_adaptor}'s default template
|
||||
arguments.
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
template <class AdaptableUnaryFunction, class Iterator>
|
||||
struct transform_iterator_generator
|
||||
{
|
||||
typedef typename AdaptableUnaryFunction::result_type value_type;
|
||||
public:
|
||||
typedef iterator_adaptor<Iterator,
|
||||
transform_iterator_policies<AdaptableUnaryFunction>,
|
||||
value_type, value_type, value_type*, std::input_iterator_tag> type;
|
||||
};
|
||||
\end{verbatim}
|
||||
}
|
||||
Alternatively, it would be nice to return by-reference for some
|
||||
iterators and by-value for others. However, the current
|
||||
\code{iterator\_\-traits} does not provide enough information make the
|
||||
choice. In addition, the lack of consistency between \code{operator[]}
|
||||
and \code{operator*} will be surprising to people. Preferably an
|
||||
iterator would either return by-value for both \code{operator*} and
|
||||
\code{operator[]} or return by-reference for both. The proposal
|
||||
in~\cite{siek01:_improved_iter_cat} would solves these problems, but
|
||||
of course that will take some time to gain acceptance.
|
||||
|
||||
As a finishing touch, we will create an
|
||||
\textsf{object generator} for the transform iterator, which
|
||||
is a function that makes it more convenient to create objects of some
|
||||
class template.
|
||||
\section{Conclusion}
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
template <class AdaptableUnaryFunction, class Iterator>
|
||||
typename transform_iterator_generator<AdaptableUnaryFunction,
|
||||
Iterator>::type
|
||||
make_transform_iterator(Iterator base,
|
||||
const AdaptableUnaryFunction& f = AdaptableUnaryFunction())
|
||||
{
|
||||
typedef typename transform_iterator_generator<AdaptableUnaryFunction,
|
||||
Iterator>::type result_t;
|
||||
return result_t(base, f);
|
||||
}
|
||||
\end{verbatim}
|
||||
}
|
||||
talk about how this approach generalizes to other things, containers,
|
||||
etc.
|
||||
|
||||
Here is an example that shows how to use a transform iterator to
|
||||
iterate through a range of numbers, multiplying each of them by 2
|
||||
and printing the result to standard output.
|
||||
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||
const int N = sizeof(x)/sizeof(int);
|
||||
std::cout << "multiplying the array by 2:" << std::endl;
|
||||
std::copy(boost::make_transform_iterator(x,
|
||||
std::bind1st(std::multiplies<int>(), 2)),
|
||||
boost::make_transform_iterator(x + N,
|
||||
std::bind1st(std::multiplies<int>(), 2)),
|
||||
std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
return 0;
|
||||
}
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
\noindent This output is:
|
||||
{\footnotesize
|
||||
\begin{verbatim}
|
||||
2 4 6 8 10 12 14 16
|
||||
\end{verbatim}
|
||||
}
|
||||
|
||||
\bibliographystyle{abbrv}
|
||||
\bibliography{refs,tmpw00}
|
||||
@ -565,4 +841,6 @@ and printing the result to standard output.
|
||||
% LocalWords: adaptors istream ostream iter MTL InputIterator adaptor const
|
||||
% LocalWords: RandomAccessIterator dereference interoperate Implementers tmpw
|
||||
% LocalWords: dereferencing adaptor's lvalues iterator's instantiation typedef
|
||||
% LocalWords: AdaptableUnaryFunction templated
|
||||
% LocalWords: AdaptableUnaryFunction templated dereferenced lvalue
|
||||
% LocalWords: parameterization implementers combinatorial InputIterators
|
||||
% LocalWords: Convertibility
|
||||
|
Reference in New Issue
Block a user