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
|
and greatly simplifies the creation of iterator types that are
|
||||||
variations on other iterators (adapted iterators). The Iterator
|
variations on other iterators (adapted iterators). The Iterator
|
||||||
Adaptor Library employs template meta-programming and is an example of
|
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
|
pattern which can be easily adapted to generate new representatives of
|
||||||
other abstract Concept families.
|
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
|
iterator is the central abstraction of the algorithms of the Standard
|
||||||
Library and creating new iterator types and adapting old ones are
|
Library and creating new iterator types and adapting old ones are
|
||||||
common tasks for C++ programmers. There are plenty of examples of
|
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{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::istream\_iterator} and
|
||||||
\code{std::ostream\_iterator}~\cite{iso98:_cpp_final_draft_standard}n to
|
\code{std::ostream\_iterator}~\cite{iso98:_cpp_final_draft_standard}
|
||||||
name a few.
|
to name a few.
|
||||||
|
|
||||||
% right here you introduce the notion of iterator adaptor as a
|
% right here you introduce the notion of iterator adaptor as a
|
||||||
% byproduct of saying something else. Should say:
|
% byproduct of saying something else. Should say:
|
||||||
|
|
||||||
An iterator adaptor's job is to adapt some \code{Base} type, often
|
In addition, large number of iterator adaptors are now in use:
|
||||||
itself an iterator, to produce a new adapted iterator that conforms to
|
iterators that adapt some \code{Base} type, often itself an iterator,
|
||||||
the Conceptual requirements of its iterator category.
|
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.
|
% although this may not be the best place for it.
|
||||||
% I'm not sure if I changed your meaning by striking ``Also'' below:
|
% 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{std::reverse\_iterator}~\cite{iso98:_cpp_final_draft_standard},
|
||||||
\code{Checked\_iter}~\cite{stroustrup00:_cpp_prog_lang}, iterators of
|
\code{Checked\_iter}~\cite{stroustrup00:_cpp_prog_lang}, iterators of
|
||||||
the View Template Library~\cite{TMPW00:Weiser}, custom and smart
|
the View Template Library~\cite{TMPW00:Weiser}, custom and smart
|
||||||
iterators~\cite{becker98:_smart_iteraters,TMPW00:Baus}, compound
|
iterators~\cite{becker98:_smart_iteraters,TMPW00:Baus}, compound
|
||||||
iterators~\cite{alexandrescu98:_compound_iters}, and several iterators
|
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
|
For an iterator to be usable with the Standard algorithms (and other
|
||||||
generic algorithms in third-party libraries), it must fulfill the
|
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
|
Perhaps the most obvious reason that implementing an iterator can
|
||||||
be tedious is that there are lots of redundant operators. That is,
|
be tedious is that there are lots of redundant operators. That is,
|
||||||
there are many operators that can be trivially defined in terms of
|
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.
|
implemented in terms of prefix \code{operator++()} as shown below.
|
||||||
|
|
||||||
{\footnotesize
|
{\footnotesize
|
||||||
@ -183,42 +184,45 @@ the \code{indirect\_iterator} is a tedious job.
|
|||||||
|
|
||||||
{\footnotesize
|
{\footnotesize
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
template <class Iterator> class indirect_iterator {
|
template <class Base> class indirect_iterator {
|
||||||
public:
|
public:
|
||||||
// Adapt the meaning of dereference
|
// Adapt the meaning of dereference
|
||||||
reference operator*() const {
|
reference operator*() const {
|
||||||
return **iter; // dereference twice
|
return **iter; // dereference twice
|
||||||
}
|
}
|
||||||
pointer operator->() const {
|
// a ``redundant'' operator
|
||||||
return &**iter; // dereference twice
|
pointer operator->() const { return &*(*this); }
|
||||||
}
|
|
||||||
// Delegating the implementation to the underlying iterator.
|
// Delegating the implementation to the underlying iterator.
|
||||||
indirect_iterator& operator++() { ++iter; return *this; }
|
indirect_iterator& operator++() { ++iter; return *this; }
|
||||||
indirect_iterator& operator--() { --iter; return *this; }
|
indirect_iterator& operator--() { --iter; return *this; }
|
||||||
// delegate for all the other operators...
|
// delegate for all the other operators...
|
||||||
private:
|
private:
|
||||||
Iterator iter;
|
Base iter;
|
||||||
};
|
};
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
}
|
}
|
||||||
|
|
||||||
% I think it would be better to use reverse_iterator as an example
|
% I think it would be better to use reverse_iterator as an example
|
||||||
% here, because it delegates more types than indirect_iterator does.
|
% here, because it delegates more types than indirect_iterator does.
|
||||||
In addition, a standard-conforming iterator must either come with a
|
% But reverse_iterator doesn't delegate many operators... it changes
|
||||||
specialization of \code{std::iterator\_traits<>} or it must define
|
% the meaning of all of them. I wonder if there's a good example
|
||||||
five nested types: \code{value\_type}, \code{reference},
|
% for both operators and typedefs.
|
||||||
\code{pointer}, \code{difference\_type}, and
|
A standard-conforming iterator must either come with a specialization
|
||||||
\code{iterator\_category}. In the example above, the last two would be
|
of \code{std::iterator\_\-traits<>} or it must define five nested
|
||||||
delegated to the \code{Base} iterator type. For many iterator
|
types: \code{value\_\-type}, \code{reference}, \code{pointer},
|
||||||
adaptors, all five must be delegated.
|
\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}
|
\subsection{Iterator Complexities}
|
||||||
|
|
||||||
In addition to the tedious aspects of iterator implementation, there
|
In addition to the tedious aspects of iterator implementation, there
|
||||||
are some complexities that trip up even the most experienced of
|
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}
|
\subsubsection{Constant/Mutable Iterator Interactions}
|
||||||
|
\label{sec:constant-mutable-iterations}
|
||||||
|
|
||||||
Iterators over containers and other sequences of stored objects
|
Iterators over containers and other sequences of stored objects
|
||||||
usually come in pairs: a constant iterator type and a mutable iterator
|
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
|
that you are implementing a container type \code{C}. Then you ought to
|
||||||
define the following four version of \code{operator==}, along with
|
define the following four version of \code{operator==}, along with
|
||||||
corresponding versions of \code{operator!=}, and (for
|
corresponding versions of \code{operator!=}, and (for
|
||||||
RandomAccessIterators), operators \code{<}, \code{>},
|
\stlconcept{RandomAccessIterator}), operators \code{<}, \code{>},
|
||||||
\code{<=}, \code{>=}, and \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
|
\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.
|
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
|
% 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?
|
% finally figured out what you were driving at. Who makes this conceptual mistake?
|
||||||
Another subtlety in the implementation of iterators is how the the
|
% It may not be worthwhile... though I've seen other grad students make
|
||||||
distinction between constant and mutable iterators affects the
|
% this mistake, and the TMPW2000 VTL paper contains this mistake.
|
||||||
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.
|
|
||||||
|
|
||||||
One common mistake is that the programmer will confuse the ideas of
|
The implementations of the constant and mutable versions of an
|
||||||
a \code{const} iterator object and a \emph{constant iterator}. Such a
|
iterator typically differ only in their \code{reference} and
|
||||||
misunderstanding can, for example, lead to a single iterator class that has
|
\code{pointer} types. Therefore it is desirable to merge the two
|
||||||
two versions of \code{operator*}, one that is a \code{const} member function
|
iterator classes into a single class template with the
|
||||||
and one that is not.
|
\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
|
{\footnotesize
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
@ -275,11 +280,6 @@ and one that is not.
|
|||||||
\end{verbatim}
|
\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
|
There should be only one \code{operator*} that returns the
|
||||||
\code{reference} type and the member function should be \code{const} since
|
\code{reference} type and the member function should be \code{const} since
|
||||||
dereferencing an iterator does not change the state of the iterator
|
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->}}
|
\subsubsection{Input Iterators and \code{operator->}}
|
||||||
|
\label{sec:operator-arrow}
|
||||||
|
|
||||||
When creating an iterator adaptor that produces an
|
When creating an iterator adaptor that produces an
|
||||||
\stlconcept{InputIterator} some extra care must be
|
\stlconcept{InputIterator} some extra care must be taken in the
|
||||||
taken in the implementation of \code{operator->}. Remember that an
|
implementation of \code{operator->}. Remember that an input iterator
|
||||||
input iterator need not iterate over stored objects: it
|
need not iterate over stored objects: it can manufacture new objects
|
||||||
can manufacture new objects when it is dereferenced as is the case for
|
when it is dereferenced as is the case for
|
||||||
\code{std::istream\_iterator}. If the iterator's \code{value\_type} is
|
\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 class type, we need to support \code{operator->}. Since the result
|
||||||
of using \code{operator->} must produce a true pointer even when
|
of using \code{operator->} must produce a true pointer even when
|
||||||
dereferencing the iterator does not yeild a true reference type, we
|
dereferencing the iterator does not yield a true reference type, we
|
||||||
need a \code{const} lvalue to which a pointer can be formed.
|
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
|
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
|
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
|
a convenient way to describe the semantics of ordinary
|
||||||
\code{operator->}, which returns a pointer: it just uses the pointer
|
\code{operator->}, which returns a pointer: it just uses the pointer
|
||||||
to perform the usual member dereferencing. It also turns out to be
|
to perform the usual member dereferencing. It also turns out to be
|
||||||
what we need to make conforming \stlconcept{InputIterators}. By making
|
what we need to make a conforming \stlconcept{InputIterator}. By
|
||||||
the return type of \code{operator->} a proxy containing an instance of
|
making the return type of \code{operator->} a proxy containing an
|
||||||
the iterator's \code{value\_type}, we can eventually form a
|
instance of the iterator's \code{value\_type}, we can eventually form
|
||||||
\code{const} pointer to the returned temporary:
|
a \code{const} pointer to the returned temporary:
|
||||||
|
|
||||||
{\footnotesize
|
{\footnotesize
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
@ -348,26 +741,24 @@ appropriate type for the result of an iterator's \code{operator->}:
|
|||||||
\end{verbatim}
|
\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,
|
category is no more refined than \stlconcept{InputIterator}. If so,
|
||||||
the appropriate \code{operator\_arrow\_proxy} is selected.
|
the appropriate \code{operator\_arrow\_proxy} is selected.
|
||||||
Convertibility is used as a criterion to allow for user-defined
|
Convertibility is used as a criterion to allow for user-defined
|
||||||
iterator categories derived from the standard ones.
|
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[]}
|
\subsubsection{Implementation 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[]}
|
The implementation of \code{operator[]} would be trivial except for
|
||||||
causes a run-time error in a certain class of situations. Suppose the
|
the issue surrounding what the return type should be. As discussed in
|
||||||
adapted iterator is reading in elements from a file and caching each
|
\S\ref{sec:iterator-bracket}, it would be dangerous to make the
|
||||||
element as a data member of the iterator.
|
\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
|
{\footnotesize
|
||||||
\begin{verbatim}
|
\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
|
temporary. The result is a dangling reference being returned from
|
||||||
\code{operator[]}.
|
\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
|
The \code{iterator\_adaptor} takes the safe route and returns the
|
||||||
% Default delegation to adapted iterator
|
result by-value. This meets the random access iterator requirements of
|
||||||
|
the Standard, which only says that the return type must be
|
||||||
% complexities:
|
``convertible to T'',
|
||||||
% 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:
|
|
||||||
|
|
||||||
{\footnotesize
|
{\footnotesize
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
template <class AdaptableUnaryFunction>
|
value_type operator[](difference_type n) const
|
||||||
struct transform_iterator_policies : public default_iterator_policies
|
{ return *(*this + n); }
|
||||||
{
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
}
|
}
|
||||||
|
|
||||||
The next step is to use the \code{iterator\_adaptor} template to
|
Under the current {C++} Standard, when using a random access iterator
|
||||||
construct the transform iterator type. The nicest way to package the
|
in a generic algorithm, you can not use \code{operator[]} for
|
||||||
construction of the transform iterator is to create a \emph{type
|
assignment (on the left hand side) but instead must write \code{*(i +
|
||||||
generator}, which is a class template whose sole purpose is to
|
n) = x}.
|
||||||
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 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
|
Alternatively, it would be nice to return by-reference for some
|
||||||
\begin{verbatim}
|
iterators and by-value for others. However, the current
|
||||||
template <class AdaptableUnaryFunction, class Iterator>
|
\code{iterator\_\-traits} does not provide enough information make the
|
||||||
struct transform_iterator_generator
|
choice. In addition, the lack of consistency between \code{operator[]}
|
||||||
{
|
and \code{operator*} will be surprising to people. Preferably an
|
||||||
typedef typename AdaptableUnaryFunction::result_type value_type;
|
iterator would either return by-value for both \code{operator*} and
|
||||||
public:
|
\code{operator[]} or return by-reference for both. The proposal
|
||||||
typedef iterator_adaptor<Iterator,
|
in~\cite{siek01:_improved_iter_cat} would solves these problems, but
|
||||||
transform_iterator_policies<AdaptableUnaryFunction>,
|
of course that will take some time to gain acceptance.
|
||||||
value_type, value_type, value_type*, std::input_iterator_tag> type;
|
|
||||||
};
|
|
||||||
\end{verbatim}
|
|
||||||
}
|
|
||||||
|
|
||||||
As a finishing touch, we will create an
|
\section{Conclusion}
|
||||||
\textsf{object generator} for the transform iterator, which
|
|
||||||
is a function that makes it more convenient to create objects of some
|
|
||||||
class template.
|
|
||||||
|
|
||||||
{\footnotesize
|
talk about how this approach generalizes to other things, containers,
|
||||||
\begin{verbatim}
|
etc.
|
||||||
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}
|
|
||||||
}
|
|
||||||
|
|
||||||
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}
|
\bibliographystyle{abbrv}
|
||||||
\bibliography{refs,tmpw00}
|
\bibliography{refs,tmpw00}
|
||||||
@ -565,4 +841,6 @@ and printing the result to standard output.
|
|||||||
% LocalWords: adaptors istream ostream iter MTL InputIterator adaptor const
|
% LocalWords: adaptors istream ostream iter MTL InputIterator adaptor const
|
||||||
% LocalWords: RandomAccessIterator dereference interoperate Implementers tmpw
|
% LocalWords: RandomAccessIterator dereference interoperate Implementers tmpw
|
||||||
% LocalWords: dereferencing adaptor's lvalues iterator's instantiation typedef
|
% 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