forked from boostorg/utility
Many edits based on review comments
[SVN r10939]
This commit is contained in:
@ -1,3 +1,29 @@
|
|||||||
|
% Current TOC outline
|
||||||
|
% 0 Abstract
|
||||||
|
% 1 Introduction
|
||||||
|
% 1.1 Redundant Operators
|
||||||
|
% 1.2 Delegation of Operators and Type Definitions
|
||||||
|
% 1.3 Iterator Implementation Complexities
|
||||||
|
% 1.3.1 Constant/Mutable Iterator Interactions
|
||||||
|
% 1.3.2 Constant/Mutable Iterator Code Duplication
|
||||||
|
% 1.3.3 Input Iterators and operator->
|
||||||
|
% 1.3.4 The Return Type of operator[] for Adaptors
|
||||||
|
% 2 The Boost iterator_adaptor Class Template
|
||||||
|
% 2.1 Iterator Policies Class
|
||||||
|
% 2.2 Default Iterator Policies Class
|
||||||
|
% 2.3 Iterator Type Generator
|
||||||
|
% 2.4 Iterator Object Generator
|
||||||
|
% 2.5 Example Use of the Transform Iterator Adaptor
|
||||||
|
% 3 The Implementation of iterator_adaptor
|
||||||
|
% 3.1 Deducing the Associates Types
|
||||||
|
% 3.1.1 Defaults for the Associated Types
|
||||||
|
% 3.1.2 Named Template Parameters
|
||||||
|
% 3.2 Core Operators
|
||||||
|
% 3.3 Redundant Operators
|
||||||
|
% 3.3.1 Implementing operator-> for Input Iterators
|
||||||
|
% 3.3.2 Implementation of operator[]
|
||||||
|
% 4. Conclusion
|
||||||
|
|
||||||
% Introduction/Motivation, etc. (Dave & Jeremy)
|
% Introduction/Motivation, etc. (Dave & Jeremy)
|
||||||
|
|
||||||
% iterator policies (Dave)
|
% iterator policies (Dave)
|
||||||
@ -67,20 +93,20 @@ Florham Park, NJ 07932, USA \\
|
|||||||
\maketitle
|
\maketitle
|
||||||
|
|
||||||
\begin{abstract}
|
\begin{abstract}
|
||||||
|
|
||||||
The iterator abstraction is one of the most commonly used in
|
The iterator abstraction is one of the most commonly used in
|
||||||
programming and a considerable amount of time is spent building new
|
programming, but implementing an iterator type that satisfies the C++
|
||||||
iterator types. However, implementing an iterator type that satisfies
|
Standard requirements can be challenging. The requirements for a
|
||||||
the C++ Standard requirements for an iterator can be
|
conforming iterator are at once subtle and tedious: subtle because
|
||||||
challenging. There are a number of common mistakes that people make,
|
there are many details to understand, and tedious because the various
|
||||||
and there are necessary complexities in a C++ Standard conforming
|
iterator operations must interact in ways that introduce redundancy
|
||||||
implementation that one would rather not have to think about. In this
|
into their implementations. This paper presents the generalized
|
||||||
paper we present the iterator type generator from the Boost Iterator
|
iterator template from the Boost Iterator Adaptor Library. In addition
|
||||||
Adaptor Library. This generator simplifies the creation of iterators;
|
to automating the error-prone and redundant job of iterator
|
||||||
it automates the error-prone and redundant parts of the implementation
|
implementation, it greatly simplifies the creation of iterator types
|
||||||
and greatly simplifies the creation of iterator types that are
|
that are variations on other iterators (adapted iterators). The
|
||||||
variations on other iterators (adapted iterators). The Iterator
|
Iterator Adaptor Library is an example of policy-based design and
|
||||||
Adaptor Library is an example of policy-based design and employs
|
employs template meta-programming. We also present the Policy Adapter
|
||||||
template meta-programming. We also present the Policy Adapter
|
|
||||||
implementation pattern, a strategy used by the library that can also
|
implementation pattern, a strategy used by the library that can also
|
||||||
be used to generate new representatives of other abstract Concept
|
be used to generate new representatives of other abstract Concept
|
||||||
families.
|
families.
|
||||||
@ -110,7 +136,12 @@ to name a few.
|
|||||||
In addition, large number of iterator adaptors are now in use:
|
In addition, large number of iterator adaptors are now in use:
|
||||||
iterators that adapt some \code{Base} type, often itself an iterator,
|
iterators that adapt some \code{Base} type, often itself an iterator,
|
||||||
to produce a new adapted iterator that conforms to the Conceptual
|
to produce a new adapted iterator that conforms to the Conceptual
|
||||||
requirements of its iterator category.
|
requirements of its iterator category\footnote{The term
|
||||||
|
``\code{Base}'' is not meant to imply the use of inheritance. We have
|
||||||
|
followed the lead of the standard library, which provides a
|
||||||
|
\code{base()} function to access the underlying iterator object of a
|
||||||
|
\code{reverse\_iterator} adaptor.}
|
||||||
|
|
||||||
%
|
%
|
||||||
% 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:
|
||||||
@ -173,13 +204,17 @@ redundant.
|
|||||||
An iterator adaptor used to adapt an underlying iterator type often
|
An iterator adaptor used to adapt an underlying iterator type often
|
||||||
changes the meaning of one or two operators while leaving the rest of
|
changes the meaning of one or two operators while leaving the rest of
|
||||||
the operators defined in the same way as in the base iterator. This
|
the operators defined in the same way as in the base iterator. This
|
||||||
is typically implemented with delegating functions. The following
|
is typically implemented with delegating functions.\footnote{Although
|
||||||
example shows an excerpt from an \code{indirect\_iterator} adaptor,
|
one might normally consider parametrized inheritance for cases where
|
||||||
which takes an iterator over pointers or smart-pointers and creates an
|
many functions must be forwarded, that is not possible for a
|
||||||
iterator over the things pointed to. The \code{operator*} and
|
generalized iterator adaptor because the underlying type may be a
|
||||||
\code{operator->} are changed to dereference twice but all the other
|
pointer} The following example shows an excerpt from an
|
||||||
operators stay the same. Writing all of the delegating functions for
|
\code{indirect\_iterator} adaptor, which takes an iterator over
|
||||||
the \code{indirect\_iterator} is a tedious job.
|
pointers or smart-pointers and creates an iterator over the things
|
||||||
|
pointed to. The \code{operator*} and \code{operator->} are changed to
|
||||||
|
dereference twice but all the other operators stay the same. Writing
|
||||||
|
all of the delegating functions for the \code{indirect\_iterator} is a
|
||||||
|
tedious job.
|
||||||
|
|
||||||
{\footnotesize
|
{\footnotesize
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
@ -190,7 +225,7 @@ the \code{indirect\_iterator} is a tedious job.
|
|||||||
return **iter; // dereference twice
|
return **iter; // dereference twice
|
||||||
}
|
}
|
||||||
// a ``redundant'' operator
|
// a ``redundant'' operator
|
||||||
pointer operator->() const { return &*(*this); }
|
pointer operator->() const { return &this->operator*(); } % dwa -- changed for clarity. I don't think the review comment was correct.
|
||||||
// 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; }
|
||||||
@ -359,15 +394,17 @@ needed by the resulting adapted iterator in the policies class rather than
|
|||||||
incorporating it into the \code{Base} type because \code{iterator\_\-adaptor}
|
incorporating it into the \code{Base} type because \code{iterator\_\-adaptor}
|
||||||
provides so many useful defaults when the \code{Base} type is an iterator.
|
provides so many useful defaults when the \code{Base} type is an iterator.
|
||||||
|
|
||||||
The policies class
|
The policies class inherits from
|
||||||
inherits from \code{default\_\-iterator\_\-policies}, which delegates
|
\code{default\_\-iterator\_\-policies}, which delegates all other
|
||||||
all other operations to the base iterator. The main event of the
|
operations to the base iterator. The main event of the
|
||||||
\code{transform\_\-iterator\_\-policies} class is the
|
\code{transform\_\-iterator\_\-policies} class is the
|
||||||
\code{dereference()} member function, which simply applies the
|
\code{dereference()} member function, which simply applies the
|
||||||
function to the dereferenced value. The base iterator object is the
|
function to the dereferenced value. The base iterator object is the
|
||||||
second argument to the \code{dereference()} function. The iterator
|
second argument to the \code{dereference()} function. The iterator
|
||||||
type is a template parameter to allow this policy class to be used
|
type is a template parameter to allow this policy class to be used
|
||||||
with any base iterator type.
|
with any base iterator type.\footnote{The term``\code{BaseIterator}''
|
||||||
|
here is meant to denote that the \code{Base} type is expected to be an
|
||||||
|
iterator.}
|
||||||
|
|
||||||
{\footnotesize
|
{\footnotesize
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
@ -387,9 +424,13 @@ with any base iterator type.
|
|||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
}
|
}
|
||||||
|
|
||||||
The \code{type<Reference>} parameter is used to convey the appropriate
|
The \code{type<Reference>} parameter is used to convey the appropriate return
|
||||||
return type to the \code{dereference()} function. This method is
|
type to the \code{dereference()} function. This method is perhaps not the most
|
||||||
perhaps not the most elegant, but it was the most portable solution.
|
elegant, but it was the most portable solution.\footnote{It would have been more
|
||||||
|
elegant to rely on the caller for explicit specification of the \code{Reference}
|
||||||
|
template argument as in
|
||||||
|
\code{policies.dereference<reference\_type>(base\_iterator)}, but that approach
|
||||||
|
proved not to to be portable to all of the targeted compilers.}
|
||||||
|
|
||||||
A policies class is required to have a default constructor because the
|
A policies class is required to have a default constructor because the
|
||||||
\code{iterator\_\-adaptor} has an instance of the policies class as a
|
\code{iterator\_\-adaptor} has an instance of the policies class as a
|
||||||
@ -438,8 +479,8 @@ namespace boost {
|
|||||||
template <class Base>
|
template <class Base>
|
||||||
void decrement(Base& x) { --x; }
|
void decrement(Base& x) { --x; }
|
||||||
|
|
||||||
template <class Base, class DifferenceType>
|
template <class Base, class Difference>
|
||||||
void advance(Base& x, DifferenceType n) { x += n; }
|
void advance(Base& x, Difference n) { x += n; }
|
||||||
|
|
||||||
template <class Difference, class Base1, class Base2>
|
template <class Difference, class Base1, class Base2>
|
||||||
Difference distance(type<Difference>, const Base1& x,
|
Difference distance(type<Difference>, const Base1& x,
|
||||||
@ -467,7 +508,7 @@ actual iterator type. The best way to package the construction of the
|
|||||||
transform iterator is to create a \emph{type generator}, which is a
|
transform iterator is to create a \emph{type generator}, which is a
|
||||||
class template whose sole purpose is to simplify the instantiation of
|
class template whose sole purpose is to simplify the instantiation of
|
||||||
some other complicated class template. It fulfills the same need as a
|
some other complicated class template. It fulfills the same need as a
|
||||||
templated typedef would if that were part of the {C++} language. The
|
template typedef would if that were part of the {C++} language. The
|
||||||
first template parameter to the generator is the type of the function
|
first template parameter to the generator is the type of the function
|
||||||
object and the second is the base iterator type. The following code
|
object and the second is the base iterator type. The following code
|
||||||
shows the type generator for the transform iterator.
|
shows the type generator for the transform iterator.
|
||||||
@ -529,22 +570,29 @@ following constructor.
|
|||||||
}
|
}
|
||||||
|
|
||||||
It would be cumbersome for the user to call this constructor since
|
It would be cumbersome for the user to call this constructor since
|
||||||
they would have to separately construct a policies object and
|
they would have to separately construct a policies object and then the
|
||||||
then the iterator object. We therefore recommend that iterator
|
iterator object. We therefore recommend that iterator implementers
|
||||||
implementers create an \emph{object generator} function for their
|
create an \emph{object generator} function for their iterator. The
|
||||||
iterator. The following is the generator function for the transform
|
following is the generator function for the transform iterator
|
||||||
iterator adaptor.
|
adaptor.\footnote{
|
||||||
|
There is precedent in the standard for calling such
|
||||||
|
an object generator, simply ``\code{transform\_iterator()}''
|
||||||
|
(e.g. \code{std::back\_inserter}), but also for the more explicit
|
||||||
|
\code{make\_} prefix (e.g. \code{std::make\_pair()}) and occasionally
|
||||||
|
for using the simple name for the adaptor type itself
|
||||||
|
(e.g. \code{std::reverse\_iterator}). In the end, the authors decided
|
||||||
|
that explicit was better than implicit. }
|
||||||
|
|
||||||
{\footnotesize
|
{\footnotesize
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
template <class AdaptableUnaryFunction, class Iterator>
|
template <class AdaptableUnaryFunction, class BaseIterator>
|
||||||
typename transform_iterator_generator<
|
typename transform_iterator_generator<
|
||||||
AdaptableUnaryFunction, Iterator>::type
|
AdaptableUnaryFunction, BaseIterator>::type
|
||||||
make_transform_iterator(Iterator base,
|
make_transform_iterator(BaseIterator base,
|
||||||
const AdaptableUnaryFunction& f = AdaptableUnaryFunction())
|
const AdaptableUnaryFunction& f = AdaptableUnaryFunction())
|
||||||
{
|
{
|
||||||
typedef typename transform_iterator_generator<AdaptableUnaryFunction,
|
typedef typename transform_iterator_generator<AdaptableUnaryFunction,
|
||||||
Iterator>::type result_t;
|
BaseIterator>::type result_t;
|
||||||
|
|
||||||
transform_iterator_policies<AdaptableUnaryFunction> policies(f);
|
transform_iterator_policies<AdaptableUnaryFunction> policies(f);
|
||||||
|
|
||||||
@ -565,9 +613,8 @@ important than implementer convenience.
|
|||||||
|
|
||||||
\subsection{Example Use of the Transform Iterator Adaptor}
|
\subsection{Example Use of the Transform Iterator Adaptor}
|
||||||
|
|
||||||
The following example shows how a transform iterator can be used to
|
This example shows how a transform iterator can be used to
|
||||||
iterate through a range of numbers, multiplying each of them by 2 and
|
negate the numbers over which it iterates.
|
||||||
printing the result to standard output.
|
|
||||||
|
|
||||||
{\footnotesize
|
{\footnotesize
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
@ -579,12 +626,11 @@ printing the result to standard output.
|
|||||||
{
|
{
|
||||||
int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||||
const int N = sizeof(x)/sizeof(int);
|
const int N = sizeof(x)/sizeof(int);
|
||||||
std::cout << "multiplying the array by 2:" << std::endl;
|
std::cout << "negating the elements of the array:" << std::endl;
|
||||||
std::copy(boost::make_transform_iterator(x,
|
std::copy(
|
||||||
std::bind1st(std::multiplies<int>(), 2)),
|
boost::make_transform_iterator(x, std::negate<int>()),
|
||||||
boost::make_transform_iterator(x + N,
|
boost::make_transform_iterator(x + N, std::negate<int>()),
|
||||||
std::bind1st(std::multiplies<int>(), 2)),
|
std::ostream_iterator<int>(std::cout, " "));
|
||||||
std::ostream_iterator<int>(std::cout, " "));
|
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -594,7 +640,7 @@ printing the result to standard output.
|
|||||||
\noindent This output is:
|
\noindent This output is:
|
||||||
{\footnotesize
|
{\footnotesize
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
2 4 6 8 10 12 14 16
|
-1 -2 -3 -4 -5 -6 -7 -8
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -602,19 +648,19 @@ printing the result to standard output.
|
|||||||
\section{The Implementation of \code{iterator\_adaptor}}
|
\section{The Implementation of \code{iterator\_adaptor}}
|
||||||
|
|
||||||
The outline for the implementation of the \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
|
class template is as follows. In the next few sections we will discuss
|
||||||
of the implementation in more depth, including how the problems
|
aspects of the implementation in more depth, including how the
|
||||||
discussed in the introduction were solved.
|
problems discussed in the introduction were solved.
|
||||||
|
|
||||||
{\footnotesize
|
{\footnotesize
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
namespace boost {
|
namespace boost {
|
||||||
template <class Base, class Policies,
|
template <class Base, class Policies,
|
||||||
class Param1 = default_argument,
|
class Value = default_argument,
|
||||||
class Param2 = default_argument,
|
class Reference = default_argument,
|
||||||
class Param3 = default_argument,
|
class Pointer = default_argument,
|
||||||
class Param4 = default_argument,
|
class Category = default_argument,
|
||||||
class Param5 = default_argument>
|
class Distance = default_argument>
|
||||||
struct iterator_adaptor {
|
struct iterator_adaptor {
|
||||||
// Deduce iterator associated types (value_type, etc.) from the
|
// Deduce iterator associated types (value_type, etc.) from the
|
||||||
// named template parameters, and resolve any defaults.
|
// named template parameters, and resolve any defaults.
|
||||||
@ -627,7 +673,7 @@ namespace boost {
|
|||||||
// optimization to conserve space. The base is ``first'' and
|
// optimization to conserve space. The base is ``first'' and
|
||||||
// the policies are ``second''.
|
// the policies are ``second''.
|
||||||
Policies& policies() { return m_iter_p.second(); }
|
Policies& policies() { return m_iter_p.second(); }
|
||||||
Base& iter() { return m_iter_p.first(); }
|
Base& base() { return m_iter_p.first(); }
|
||||||
// and similarly for const...
|
// and similarly for const...
|
||||||
};
|
};
|
||||||
// Core binary operators.
|
// Core binary operators.
|
||||||
@ -636,7 +682,7 @@ namespace boost {
|
|||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
}
|
}
|
||||||
|
|
||||||
\subsection{Deducing the Associates Types}
|
\subsection{Deducing the Associated Types}
|
||||||
|
|
||||||
Iterators have five associated types: \code{value\_\-type},
|
Iterators have five associated types: \code{value\_\-type},
|
||||||
\code{reference}, \code{pointer}, \code{iterator\_\-category}, and
|
\code{reference}, \code{pointer}, \code{iterator\_\-category}, and
|
||||||
@ -750,7 +796,7 @@ the case with the \code{reference} type in the implementation of
|
|||||||
{\footnotesize
|
{\footnotesize
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
reference operator*() const {
|
reference operator*() const {
|
||||||
return policies().dereference(type<reference>(), iter());
|
return policies().dereference(type<reference>(), base());
|
||||||
}
|
}
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
}
|
}
|
||||||
@ -764,22 +810,23 @@ iterator interactions, avoiding the combinatorial explosion discussed
|
|||||||
in \S\ref{sec:constant-mutable-iterations}. Note that we only use a
|
in \S\ref{sec:constant-mutable-iterations}. Note that we only use a
|
||||||
single \code{Policies} template parameter: this restricts iterator
|
single \code{Policies} template parameter: this restricts iterator
|
||||||
interaction to those iterators with the same policies class. This is
|
interaction to those iterators with the same policies class. This is
|
||||||
not restrictive as it should be, however the only real disadvantage to
|
not as restrictive as it probably should be, but most iterator
|
||||||
not being restrictive enough is in the kind of error message the user
|
interaction errors will be caught anyway, when the policies are applied
|
||||||
will see when misusing two unrelated iterators. Instead of an
|
disadvantage to not being restrictive enough is in the kind of error
|
||||||
``operator not found'' message they will see an error message from
|
message the user will see when misusing two unrelated
|
||||||
inside the iterator adaptor.
|
iterators. Instead of an ``operator not found'' message they will see
|
||||||
|
an error message from inside the iterator adaptor.
|
||||||
|
|
||||||
{\footnotesize
|
{\footnotesize
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
template <class Iter1, class Iter2, class Policies, class V1, class V2,
|
template <class Base1, class Base2, class Policies, class V1, class V2,
|
||||||
class R1, class R2, class P1, class P2, class C1, class C2,
|
class R1, class R2, class P1, class P2, class C1, class C2,
|
||||||
class D1, class D2>
|
class D1, class D2>
|
||||||
bool operator<(
|
bool operator<(
|
||||||
const iterator_adaptor<Iter1,Policies,V1,R1,P1,C1,D1>& x,
|
const iterator_adaptor<Base1,Policies,V1,R1,P1,C1,D1>& x,
|
||||||
const iterator_adaptor<Iter2,Policies,V2,R2,P2,C2,D2>& y)
|
const iterator_adaptor<Base2,Policies,V2,R2,P2,C2,D2>& y)
|
||||||
{
|
{
|
||||||
return x.policies().less(x.iter(), y.iter());
|
return x.policies().less(x.base(), y.base());
|
||||||
}
|
}
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
}
|
}
|
||||||
@ -904,8 +951,8 @@ the data member. Now consider what happens inside the
|
|||||||
|
|
||||||
{\footnotesize
|
{\footnotesize
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
template <class Iterator> class iterator_adaptor {
|
template <class BaseIterator> class my_iterator_adaptor {
|
||||||
Iterator iter;
|
BaseIterator iter;
|
||||||
public:
|
public:
|
||||||
reference operator[](difference_type n) const {
|
reference operator[](difference_type n) const {
|
||||||
return *(iter + n);
|
return *(iter + n);
|
||||||
@ -932,14 +979,13 @@ the Standard, which only says that the return type must be
|
|||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
}
|
}
|
||||||
|
|
||||||
Under the current {C++} Standard, when using a random access iterator
|
Under the current {C++} Standard, you cannot assign into the result of
|
||||||
in a generic algorithm, you can not use \code{operator[]} for
|
\code{operator[]} applied to a generic random access iterator,
|
||||||
assignment (on the left hand side) but instead must write \code{*(i +
|
but instead must write \code{*(i + n) = x}.
|
||||||
n) = x}.
|
|
||||||
|
|
||||||
It would be nice to return by-reference for iterators that can support
|
It would be nice to return by-reference for iterators that can support
|
||||||
it, and by-value for the rest. However, the current
|
it, and by-value for the rest. However, the current
|
||||||
\code{iterator\_\-traits} does not provide enough information make the
|
\code{iterator\_\-traits} does not provide enough information to make the
|
||||||
choice.
|
choice.
|
||||||
|
|
||||||
% Jeremy: I didn't agree with this part, so commented it out
|
% Jeremy: I didn't agree with this part, so commented it out
|
||||||
|
Reference in New Issue
Block a user