forked from boostorg/utility
intermediate state checkin
[SVN r10988]
This commit is contained in:
@@ -74,6 +74,15 @@
|
|||||||
|
|
||||||
\documentclass{netobjectdays}
|
\documentclass{netobjectdays}
|
||||||
|
|
||||||
|
\newcommand{\Cpp}{C\kern-0.05em\texttt{+\kern-0.03em+}}
|
||||||
|
\newcommand{\iteratoradaptor}{\code{iterator\_\-adaptor}}
|
||||||
|
\newcommand{\valuetype}{\code{value\_\-type}}
|
||||||
|
\newcommand{\differencetype}{\code{difference\_\-type}}
|
||||||
|
\newcommand{\iteratorcategory}{\code{iterator\_\-category}}
|
||||||
|
\newcommand{\iteratortraits}{\code{iterator\_\-traits}}
|
||||||
|
\newcommand{\constiterator}{\code{const\_\-iterator}}
|
||||||
|
\newcommand{\reverseiterator}{\code{reverse\_\-iterator}}
|
||||||
|
|
||||||
\input{defs}
|
\input{defs}
|
||||||
|
|
||||||
\begin{document}
|
\begin{document}
|
||||||
@@ -92,24 +101,22 @@ Florham Park, NJ 07932, USA \\
|
|||||||
|
|
||||||
\maketitle
|
\maketitle
|
||||||
|
|
||||||
\begin{abstract}
|
\begin{abstract} $\!$The iterator abstraction is one of the most
|
||||||
|
commonly used in programming, but implementing an iterator type can be
|
||||||
The iterator abstraction is one of the most commonly used in
|
challenging. The requirements for a standard-conforming iterator are
|
||||||
programming, but implementing an iterator type that satisfies the C++
|
at once tedious and subtle: tedious because much of an iterator's rich
|
||||||
Standard requirements can be challenging. The requirements for a
|
interface is ``boilerplate'' surrounding a few core opertions, and
|
||||||
conforming iterator are at once subtle and tedious: subtle because
|
subtle because of the intricate details involved in getting that
|
||||||
there are many details to understand, and tedious because the various
|
interface right. This paper presents the generalized iterator template
|
||||||
iterator operations must interact in ways that introduce redundancy
|
from the Boost Iterator Adaptor Library. In addition to automating the
|
||||||
into their implementations. This paper presents the generalized
|
error-prone and redundant job of implementing new iterator types, the
|
||||||
iterator template from the Boost Iterator Adaptor Library. In addition
|
library simplifies the creation of iterator types that are variations
|
||||||
to automating the error-prone and redundant job of iterator
|
on other iterators (adapted iterators) and generators of new iterator
|
||||||
implementation, it greatly simplifies the creation of iterator types
|
families (iterator adaptors). The Iterator Adaptor Library is an
|
||||||
that are variations on other iterators (adapted iterators). The
|
example of policy-based design and employs template
|
||||||
Iterator Adaptor Library is an example of policy-based design and
|
meta-programming. We also present the Policy Adapter implementation
|
||||||
employs template meta-programming. We also present the Policy Adapter
|
pattern, a strategy used by the library that can also be used to
|
||||||
implementation pattern, a strategy used by the library that can also
|
generate new representatives of other abstract Concept families.
|
||||||
be used to generate new representatives of other abstract Concept
|
|
||||||
families.
|
|
||||||
\end{abstract}
|
\end{abstract}
|
||||||
|
|
||||||
|
|
||||||
@@ -119,48 +126,179 @@ families.
|
|||||||
%- extensions from base operations to other operations make it
|
%- extensions from base operations to other operations make it
|
||||||
% easier to create iterators
|
% easier to create iterators
|
||||||
|
|
||||||
Iterators play an important role in modern C++ programing. The
|
Iterators play an important role in modern \Cpp\ 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 is a common task for C++
|
Library, allowing algorithms to be re-used in in a wide variety of
|
||||||
programmers. There are plenty of examples of iterators in the
|
contexts.
|
||||||
literature: the
|
|
||||||
\code{line\_iterator}~\cite{austern99:_gener_progr_stl},
|
|
||||||
\code{Constant\_iterator}~\cite{koenig97:_rumin_cpp},
|
|
||||||
\code{std::istream\_iterator} and
|
|
||||||
\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
|
\subsection{Iterators}
|
||||||
% byproduct of saying something else. Should say:
|
|
||||||
|
|
||||||
In addition, large number of iterator adaptors are now in use:
|
The power of iterators derives from several key
|
||||||
iterators that adapt some \code{Base} type, often itself an iterator,
|
features:\begin{itemize}
|
||||||
to produce a new adapted iterator that conforms to the Conceptual
|
|
||||||
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.}
|
|
||||||
|
|
||||||
%
|
\item Iterators form a rich \emph{family} of Concepts
|
||||||
% although this may not be the best place for it.
|
whose functionality varies along several axes: movement,
|
||||||
% I'm not sure if I changed your meaning by striking ``Also'' below:
|
dereferencing, and type exposure.
|
||||||
%
|
|
||||||
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
|
|
||||||
from the MTL~\cite{siek99:_scitools}.
|
|
||||||
|
|
||||||
For an iterator to be usable with the Standard algorithms (and other
|
\item The iterator concepts of the \Cpp\
|
||||||
generic algorithms in third-party libraries), it must fulfill the
|
standard form a refinement hierarchy which allows the same basic
|
||||||
Standard requirements for an iterator type, which range from the few
|
interface elements to implement diverse functionality.
|
||||||
requirements of an \stlconcept{InputIterator} to the many requirements
|
|
||||||
of a \stlconcept{RandomAccessIterator}. Implementing an iterator class
|
\item Because
|
||||||
that meets these requirements is a tedious and error-prone task
|
built-in pointer types model the \stlconcept{RandomAccessIterator}
|
||||||
despite the fact that most iterators are conceptually simple.
|
Concept, iterators can be both efficient and convenient to use.
|
||||||
|
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
The \Cpp\ Standard Library contains a wide variety of useful
|
||||||
|
iterators. Every one of the standard containers comes with constant
|
||||||
|
and mutable iterators, and also \code{reverse\_} versions which
|
||||||
|
traverse the container in the opposite direction. The Standard also
|
||||||
|
supplies \code{istream\_\-iterator} and \code{ostream\_\-iterator} for
|
||||||
|
reading from and writing to streams, \code{insert\_iterator} and
|
||||||
|
\code{back\_insert\_iterator} for inserting elements in containers,
|
||||||
|
and \code{raw\_\-storage\_\-iterator} for initializing raw
|
||||||
|
memory~\cite{iso98:_cpp_final_draft_standard}.
|
||||||
|
|
||||||
|
Despite the many iterators supplied by the Standard Library, many
|
||||||
|
obvious iterators are missing, and creating new iterator types is
|
||||||
|
still a common task for \Cpp\ programmers. The literature documents
|
||||||
|
several of these, for example
|
||||||
|
\code{line\_iterator}~\cite{austern99:_gener_progr_stl}
|
||||||
|
\code{Constant\_iterator}~\cite{koenig97:_rumin_cpp}. The iterator
|
||||||
|
abstraction is so powerful, however, that we expect programmers will
|
||||||
|
always invent new iterator types.
|
||||||
|
|
||||||
|
\subsection{Adaptors}
|
||||||
|
|
||||||
|
Because iterators combine traversal, indirection, and type exposure,
|
||||||
|
it is common to want to adapt one iterator to form a new one. This
|
||||||
|
strategy allows one to reuse some of original iterator's axes of
|
||||||
|
variation while redefining others. For example, the Standard provides
|
||||||
|
\reverseiterator{}, which adapts any \stlconcept{BidirectionalIterator}
|
||||||
|
by inverting its direction of traversal.
|
||||||
|
|
||||||
|
As with plain iterators, iterator adaptors defined outside the
|
||||||
|
Standard have become commonplace in the literature:\begin{itemize}
|
||||||
|
|
||||||
|
\item \code{Checked\_iter}~\cite{stroustrup00:_cpp_prog_lang} adds
|
||||||
|
bounds-checking to an existing iterator.
|
||||||
|
|
||||||
|
\item The iterators of the View Template
|
||||||
|
Library~\cite{TMPW00:Weiser}, which adapts containers, are themselves
|
||||||
|
adaptors over the underlying iterators.
|
||||||
|
|
||||||
|
\item smart iterators~\cite{becker98:_smart_iterators},
|
||||||
|
which adapt an iterator's dereferencing behavior by applying a
|
||||||
|
function object to the object being referenced and returning the
|
||||||
|
result.
|
||||||
|
|
||||||
|
\item Custom iterators~\cite{TMPW00:Baus},
|
||||||
|
in which a variety of adaptor types are enumerated.
|
||||||
|
|
||||||
|
% Jeremy, I don't know what to say about these two. Can you fill it in?
|
||||||
|
\item compound iterators~\cite{alexandrescu98:_compound_iters}
|
||||||
|
|
||||||
|
\item Several iterators from the MTL~\cite{siek99:_scitools}.
|
||||||
|
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\section{The Boost Iterator Adaptor Library}
|
||||||
|
|
||||||
|
% Do we need a section body?
|
||||||
|
In this section, we present the Boost Iterator Adaptor Library.
|
||||||
|
|
||||||
|
\subsection{Overall Design}
|
||||||
|
|
||||||
|
To automate this repetitive work, one would need a generator of new
|
||||||
|
iterator types that can accomodate all the ways in which iterators
|
||||||
|
vary. One could then make new iterators with relative ease, specifying
|
||||||
|
the parts that matter and letting the library do the rest. To that
|
||||||
|
end, the library provides a fully-generalized iterator called
|
||||||
|
\iteratoradaptor{}. The \iteratoradaptor\ class template adapts a
|
||||||
|
\code{Base} type, (usually an iterator), to produce a new adapted
|
||||||
|
iterator type.\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 \reverseiterator\ adaptor.}
|
||||||
|
|
||||||
|
\subsubsection{Core Elements of the Concept}
|
||||||
|
|
||||||
|
The first step in designing such a generalized Model is to identify
|
||||||
|
the core elements of its interface. We have identified the following
|
||||||
|
core behaviors for iterators:\begin{itemize}
|
||||||
|
\item dereferencing
|
||||||
|
\item incrementing
|
||||||
|
\item decrementing
|
||||||
|
\item equality comparison
|
||||||
|
\item random-access motion
|
||||||
|
\item distance measurement
|
||||||
|
\item ordered comparison
|
||||||
|
%% Yikes, Jeremy! I think that including both less and distance in the
|
||||||
|
%% design might be a design mistake. Doesn't that introduce redundancy?
|
||||||
|
%% Shouldn't operator<() be implemented in terms of distance?
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
In addition to the behaviors listed above, the core interface elements
|
||||||
|
include the associated types exposed through
|
||||||
|
\iteratortraits{}: \valuetype{}, \code{reference}, \code{pointer}, and
|
||||||
|
\iteratorcategory{}. The library supports two ways of specifying
|
||||||
|
these: as traditional and also as \emph{named} template parameters
|
||||||
|
(described below), and uses a system of smart defaults which in most
|
||||||
|
cases reduces the number of these types that must be specified.
|
||||||
|
|
||||||
|
\subsubsection{From Building Models to Building Adaptors}
|
||||||
|
|
||||||
|
A generalized iterator is useful, but a generalized iterator
|
||||||
|
\emph{adaptor} would be even more useful. One could then build
|
||||||
|
specialized adaptors to generate new families of iterator instances
|
||||||
|
based on existing iterators. In the Boost Iterator Adaptor Library,
|
||||||
|
the role of adaptor is also played by the \iteratoradaptor\ class
|
||||||
|
template. The behaviors of \iteratoradaptor{} instances are supplied
|
||||||
|
through a Policies class~\cite{alexandrescu01:_modern_cpp_design}
|
||||||
|
which allows allows users to specialize adaptation. They go beyond
|
||||||
|
generating new iterator types to easily generating new iterator
|
||||||
|
adaptor families.
|
||||||
|
|
||||||
|
The library contains several examples of specialized adaptors which
|
||||||
|
were quickly implemented using \iteratoradaptor{}:\begin{itemize}
|
||||||
|
|
||||||
|
\item Indirect Iterator Adaptor, which iterates over iterators, pointers, or
|
||||||
|
smart pointers and applies an extra level of dereferencing.
|
||||||
|
|
||||||
|
\item Reverse Iterator Adaptor, which inverts the direction of a
|
||||||
|
\code{Base} iterator's motion.
|
||||||
|
|
||||||
|
\item Transform Iterator Adaptor, which applies a user-defined
|
||||||
|
function object to the underlying values when dereferenced. We will
|
||||||
|
show how this adaptor is implemented below.
|
||||||
|
|
||||||
|
\item Projection Iterator Adaptor, which is similar to Transform
|
||||||
|
Iterator Adaptor except that when dereferenced it returns by-reference
|
||||||
|
instead of by-value.
|
||||||
|
|
||||||
|
\item Filter Iterator Adaptor, which view of an iterator range in
|
||||||
|
which some elements of the range are skipped over.
|
||||||
|
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
Based on the examples in the library, users have generated many new
|
||||||
|
adaptors, among them a permutation adaptor which applies some
|
||||||
|
permutation to a \stlconcept{RandomAccessIterator}, and a strided
|
||||||
|
adaptor, which adapts a \stlconcept{RandomAccessIterator} by
|
||||||
|
multiplying its unit of motion by a constant factor.
|
||||||
|
|
||||||
|
% In addition, large number of iterator adaptors are now in use:
|
||||||
|
% iterators that that conforms to the Conceptual
|
||||||
|
% requirements of its iterator category
|
||||||
|
|
||||||
|
% For an iterator to be usable with the Standard algorithms (and other
|
||||||
|
% generic algorithms in third-party libraries), it must fulfill the
|
||||||
|
% Standard requirements for an iterator type, which range from the few
|
||||||
|
% requirements of an \stlconcept{InputIterator} to the many requirements
|
||||||
|
% of a \stlconcept{RandomAccessIterator}. Implementing an iterator class
|
||||||
|
% that meets these requirements is a tedious and error-prone task
|
||||||
|
% despite the fact that most iterators are conceptually simple.
|
||||||
|
|
||||||
\subsection{Redundant Operators}
|
\subsection{Redundant Operators}
|
||||||
|
|
||||||
@@ -243,8 +381,8 @@ tedious job.
|
|||||||
% for both operators and typedefs.
|
% for both operators and typedefs.
|
||||||
A standard-conforming iterator must either come with a specialization
|
A standard-conforming iterator must either come with a specialization
|
||||||
of \code{std::iterator\_\-traits<>} or it must define five nested
|
of \code{std::iterator\_\-traits<>} or it must define five nested
|
||||||
types: \code{value\_\-type}, \code{reference}, \code{pointer},
|
types: \valuetype{}, \code{reference}, \code{pointer},
|
||||||
\code{difference\_\-type}, and \code{iterator\_\-category}. In the
|
\differencetype{}, and \iteratorcategory{}. In the
|
||||||
example above, the last two would be delegated to the \code{Base}
|
example above, the last two would be delegated to the \code{Base}
|
||||||
iterator type. For many iterator adaptors, all five must be delegated.
|
iterator type. For many iterator adaptors, all five must be delegated.
|
||||||
|
|
||||||
@@ -334,7 +472,7 @@ When creating an iterator adaptor that produces an
|
|||||||
implementation of \code{operator->}. Remember that an input iterator
|
implementation of \code{operator->}. Remember that an input iterator
|
||||||
need not iterate over stored objects: it can manufacture new objects
|
need not iterate over stored objects: it 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 \valuetype\ 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 yield a true reference type, we
|
dereferencing the iterator does not yield a true reference type, we
|
||||||
@@ -345,12 +483,12 @@ need a \code{const} lvalue to which a pointer can be formed. In
|
|||||||
\subsubsection{The Return Type of \code{operator[]} for Adaptors}
|
\subsubsection{The Return Type of \code{operator[]} for Adaptors}
|
||||||
\label{sec:operator-bracket}
|
\label{sec:operator-bracket}
|
||||||
|
|
||||||
The C++ Standard specifies that the return type of \code{operator[]}
|
The \Cpp\ Standard specifies that the return type of \code{operator[]}
|
||||||
of a random access iterator must be ``convertible to \code{T}''. This
|
of a random access iterator must be ``convertible to \code{T}''. This
|
||||||
is a rather lenient requirement since \code{operator*} is required to
|
is a rather lenient requirement since \code{operator*} is required to
|
||||||
return the exact type \code{T\&}, and one might think that
|
return the exact type \code{T\&}, and one might think that
|
||||||
\code{operator[]} and \code{operator*} should be same in this respect.
|
\code{operator[]} and \code{operator*} should be same in this respect.
|
||||||
The C++ Standards Committee is currently debating as to whether the
|
The \Cpp\ Standards Committee is currently debating as to whether the
|
||||||
random access iterator requirements should be changed.
|
random access iterator requirements should be changed.
|
||||||
|
|
||||||
To complicate the matter, returning \code{T\&} from \code{operator[]}
|
To complicate the matter, returning \code{T\&} from \code{operator[]}
|
||||||
@@ -366,17 +504,17 @@ discuss this in detail in \S\ref{sec:op-bracket-impl}.
|
|||||||
% const/mutable iterator distinction
|
% const/mutable iterator distinction
|
||||||
% input iterator \code{operator->}
|
% input iterator \code{operator->}
|
||||||
|
|
||||||
\section{The Boost \code{iterator\_adaptor} Class Template}
|
\section{The Boost \iteratoradaptor\ Class Template}
|
||||||
|
|
||||||
The \code{iterator\_\-adaptor} class template simplifies the creation
|
The \iteratoradaptor\ class template simplifies the creation
|
||||||
of iterators by automating the implementation of redundant operators
|
of iterators by automating the implementation of redundant operators
|
||||||
and delegating functions and by taking care of the complex details of
|
and delegating functions and by taking care of the complex details of
|
||||||
iterator implementation.
|
iterator implementation.
|
||||||
|
|
||||||
The central design feature of \code{iterator\_\-adaptor} is the
|
The central design feature of \iteratoradaptor\ is the
|
||||||
parameterization by an iterator policies class. The policies class is
|
parameterization by an iterator policies class. The policies class is
|
||||||
the primary communication mechanism between the iterator implementer
|
the primary communication mechanism between the iterator implementer
|
||||||
and the \code{iterator\_\-adaptor}; it specifies how the new iterator
|
and the \iteratoradaptor{}; it specifies how the new iterator
|
||||||
type is different from the \code{Base} type. Unlike the policy classes
|
type is different from the \code{Base} type. Unlike the policy classes
|
||||||
in~\cite{alexandrescu01:_modern_cpp_design}, we group several policies
|
in~\cite{alexandrescu01:_modern_cpp_design}, we group several policies
|
||||||
into a single class as this proved more convenient for iterator
|
into a single class as this proved more convenient for iterator
|
||||||
@@ -391,7 +529,7 @@ by dereferencing the base iterator. The
|
|||||||
object type, and a function object is stored as a data member of the policies
|
object type, and a function object is stored as a data member of the policies
|
||||||
class. When adapting an underlying iterator, it is easiest to store any extra state
|
class. When adapting an underlying iterator, it is easiest to store any extra state
|
||||||
needed by the resulting adapted iterator in the policies class rather than
|
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 \iteratoradaptor\
|
||||||
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 inherits from
|
The policies class inherits from
|
||||||
@@ -433,7 +571,7 @@ template argument as in
|
|||||||
proved not to to be portable to all of the targeted compilers.}
|
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
|
\iteratoradaptor\ has an instance of the policies class as a
|
||||||
data member, and iterators are required to have default constructors
|
data member, and iterators are required to have default constructors
|
||||||
thereby requiring the policies class to also have a default
|
thereby requiring the policies class to also have a default
|
||||||
constructor.
|
constructor.
|
||||||
@@ -445,7 +583,7 @@ applying a function to the result of dereferencing the base iterator.
|
|||||||
Next we will take a closer look at the
|
Next we will take a closer look at the
|
||||||
\code{default\_\-iterator\_\-policies} class and then in
|
\code{default\_\-iterator\_\-policies} class and then in
|
||||||
\S\ref{sec:iter-type-generator} we will show how the transform
|
\S\ref{sec:iter-type-generator} we will show how the transform
|
||||||
iterator type is constructed using \code{iterator\_\-adaptor}.
|
iterator type is constructed using \iteratoradaptor{}.
|
||||||
|
|
||||||
|
|
||||||
\subsection{Default Iterator Policies Class}
|
\subsection{Default Iterator Policies Class}
|
||||||
@@ -503,12 +641,12 @@ namespace boost {
|
|||||||
\label{sec:iter-type-generator}
|
\label{sec:iter-type-generator}
|
||||||
|
|
||||||
With the policy class for the transform iterator complete, the next
|
With the policy class for the transform iterator complete, the next
|
||||||
step is to use the \code{iterator\_adaptor} template to construct the
|
step is to use the \iteratoradaptor\ template to construct the
|
||||||
actual iterator type. The best way to package the construction of 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
|
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
|
||||||
template typedef would if that were part of the {C++} language. The
|
template typedef would if that were part of the \Cpp\ 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.
|
||||||
@@ -528,29 +666,29 @@ shows the type generator for the transform iterator.
|
|||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
}
|
}
|
||||||
|
|
||||||
We use \code{iterator\_adaptor} to define the transform iterator type
|
We use \iteratoradaptor\ to define the transform iterator type
|
||||||
as a nested \code{typedef} inside the
|
as a nested \code{typedef} inside the
|
||||||
\code{transform\_\-iterator\_\-generator} class. The first parameter
|
\code{transform\_\-iterator\_\-generator} class. The first parameter
|
||||||
to \code{iterator\_\-adaptor} is the base iterator type and the second
|
to \iteratoradaptor\ is the base iterator type and the second
|
||||||
is the policies class. The remaining parameters specify the iterators
|
is the policies class. The remaining parameters specify the iterators
|
||||||
associated types and are given as \emph{named parameters}. We will
|
associated types and are given as \emph{named parameters}. We will
|
||||||
discuss this technique in \S\ref{sec:named-template-parameters}.
|
discuss this technique in \S\ref{sec:named-template-parameters}.
|
||||||
|
|
||||||
The \code{iterator\_category} is set to
|
The \iteratorcategory\ is set to
|
||||||
\code{std::input\_\-iterator\_\-tag} because the function object may
|
\code{std::input\_\-iterator\_\-tag} because the function object may
|
||||||
return by-value. For the same reason the \code{reference} type (which
|
return by-value. For the same reason the \code{reference} type (which
|
||||||
will be the return type of \code{operator*}) is set to \code{val\_t}
|
will be the return type of \code{operator*}) is set to \code{val\_t}
|
||||||
(and not \code{val\_t\&}). There are two parameters that are left out:
|
(and not \code{val\_t\&}). There are two parameters that are left out:
|
||||||
the \code{pointer} type defaults to \code{value\_type*} and the
|
the \code{pointer} type defaults to \code{value\_type*} and the
|
||||||
\code{difference\_\-type} defaults to the \code{difference\_\-type} of
|
\differencetype{} defaults to the \differencetype{} of
|
||||||
the base iterator.
|
the base iterator.
|
||||||
|
|
||||||
It is tempting to create a \code{transform\_\-iterator} by deriving
|
It is tempting to create a \code{transform\_\-iterator} by deriving
|
||||||
from \code{iterator\_\-adaptor} (as an alternative to using the
|
from \iteratoradaptor\ (as an alternative to using the
|
||||||
generator). This approach does not work, for example, because the
|
generator). This approach does not work, for example, because the
|
||||||
return type of \code{operator++} of an iterator is required to be the
|
return type of \code{operator++} of an iterator is required to be the
|
||||||
same iterator type, but in this case the return type would be
|
same iterator type, but in this case the return type would be
|
||||||
\code{iterator\_\-adaptor} and not \code{transform\_\-iterator}.
|
\iteratoradaptor\ and not \code{transform\_\-iterator}.
|
||||||
|
|
||||||
%It
|
%It
|
||||||
%would be possible to arrange for using inheritance by applying the
|
%would be possible to arrange for using inheritance by applying the
|
||||||
@@ -560,7 +698,7 @@ same iterator type, but in this case the return type would be
|
|||||||
\label{sec:iter-object-generator}
|
\label{sec:iter-object-generator}
|
||||||
|
|
||||||
The next question is how users of the transform iterator will
|
The next question is how users of the transform iterator will
|
||||||
construct the iterator. The \code{iterator\_\-adaptor} class has the
|
construct the iterator. The \iteratoradaptor\ class has the
|
||||||
following constructor.
|
following constructor.
|
||||||
|
|
||||||
{\footnotesize
|
{\footnotesize
|
||||||
@@ -602,7 +740,7 @@ that explicit was better than implicit. }
|
|||||||
}
|
}
|
||||||
|
|
||||||
An alternative solution to using object generating functions would be
|
An alternative solution to using object generating functions would be
|
||||||
to have a constructor in \code{iterator\_adaptor} that takes arbitrary
|
to have a constructor in \iteratoradaptor\ that takes arbitrary
|
||||||
arguments (the constructor would be templated). The arguments would
|
arguments (the constructor would be templated). The arguments would
|
||||||
then be passed as a heterogeneous value list~\cite{TMPW00:Eisenecker}
|
then be passed as a heterogeneous value list~\cite{TMPW00:Eisenecker}
|
||||||
to the policies class. This would remove the need for object
|
to the policies class. This would remove the need for object
|
||||||
@@ -645,9 +783,9 @@ negate the numbers over which it iterates.
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
\section{The Implementation of \code{iterator\_adaptor}}
|
\section{The Implementation of \iteratoradaptor{}}
|
||||||
|
|
||||||
The outline for the implementation of the \code{iterator\_adaptor}
|
The outline for the implementation of the \iteratoradaptor\
|
||||||
class template is as follows. In the next few sections we will discuss
|
class template is as follows. In the next few sections we will discuss
|
||||||
aspects of the implementation in more depth, including how the
|
aspects of the implementation in more depth, including how the
|
||||||
problems discussed in the introduction were solved.
|
problems discussed in the introduction were solved.
|
||||||
@@ -685,9 +823,9 @@ namespace boost {
|
|||||||
|
|
||||||
\subsection{Deducing the Associated Types}
|
\subsection{Deducing the Associated Types}
|
||||||
|
|
||||||
Iterators have five associated types: \code{value\_\-type},
|
Iterators have five associated types: \valuetype{},
|
||||||
\code{reference}, \code{pointer}, \code{iterator\_\-category}, and
|
\code{reference}, \code{pointer}, \iteratorcategory{}, and
|
||||||
\code{difference\_\-type}. Each of these types must either be supplied
|
\differencetype{}. Each of these types must either be supplied
|
||||||
by the user, using the named parameter technique described below in
|
by the user, using the named parameter technique described below in
|
||||||
\S\ref{sec:named-template-parameters}, or a default must be computed
|
\S\ref{sec:named-template-parameters}, or a default must be computed
|
||||||
for the type.
|
for the type.
|
||||||
@@ -698,14 +836,14 @@ Because an iterator has so many type parameters, the order and
|
|||||||
semantics of the associated type parameters was carefully chosen so
|
semantics of the associated type parameters was carefully chosen so
|
||||||
that users would be able to use as many defaults as possible. The list
|
that users would be able to use as many defaults as possible. The list
|
||||||
of associated types begins with the most fundamental element, the
|
of associated types begins with the most fundamental element, the
|
||||||
iterator's \code{value\_\-type}. If no \code{Value} parameter is supplied,
|
iterator's \valuetype{}. If no \code{Value} parameter is supplied,
|
||||||
the \code{Base} type is assumed to be an iterator, and the adapted
|
the \code{Base} type is assumed to be an iterator, and the adapted
|
||||||
iterator takes its \code{value\_type} from the \code{Base}
|
iterator takes its \valuetype\ from the \code{Base}
|
||||||
iterator's \code{iterator\_traits}. However, if the \code{Value} parameter \emph{is} supplied,
|
iterator's \iteratortraits{}. However, if the \code{Value} parameter \emph{is} supplied,
|
||||||
an adjustment is made which allows the user to more easily create a
|
an adjustment is made which allows the user to more easily create a
|
||||||
constant iterator: if the \code{Value} parameter is \code{const T},
|
constant iterator: if the \code{Value} parameter is \code{const T},
|
||||||
the \code{value\_type} will just be \code{T}.Perhaps
|
the \valuetype\ will just be \code{T}.Perhaps
|
||||||
strangely, a constant iterator's \code{value\_type} should never be
|
strangely, a constant iterator's \valuetype\ should never be
|
||||||
\code{const}, because it would prevent algorithms from declaring
|
\code{const}, because it would prevent algorithms from declaring
|
||||||
modifiable temporary objects which are copied from dereferenced
|
modifiable temporary objects which are copied from dereferenced
|
||||||
iterators:
|
iterators:
|
||||||
@@ -735,24 +873,23 @@ default to simply \code{Value*} and \code{Value\&} respectively
|
|||||||
(without the \code{const}-ness stripped). Otherwise, as above the
|
(without the \code{const}-ness stripped). Otherwise, as above the
|
||||||
\code{Base} type is assumed to be an iterator and the \code{pointer}
|
\code{Base} type is assumed to be an iterator and the \code{pointer}
|
||||||
and \code{reference} types are taken from its
|
and \code{reference} types are taken from its
|
||||||
\code{iterator\_\-traits}.
|
\iteratortraits{}.
|
||||||
|
|
||||||
Since these defaults correspond to the required relationships between
|
Since these defaults correspond to the required relationships between
|
||||||
the \code{reference}, \code{pointer}, \code{value\_type} for all
|
the \code{reference}, \code{pointer}, \valuetype\ for all
|
||||||
constant and mutable \stlconcept{ForwardIterator}s, it is often
|
constant and mutable \stlconcept{ForwardIterator}s, it is often
|
||||||
sufficient to supply just the \code{Value} parameter when there is no
|
sufficient to supply just the \code{Value} parameter when there is no
|
||||||
\code{Base} iterator with appropriate
|
\code{Base} iterator with appropriate
|
||||||
\code{iterator\_traits}.\footnote{The \code{Reference} parameter
|
\iteratortraits{}.\footnote{The \code{Reference} parameter
|
||||||
precedes the \code{Pointer} parameter because it must be often
|
precedes the \code{Pointer} parameter because it must be often
|
||||||
customized for \stlconcept{OutputIterator}s and other iterator types
|
customized for \stlconcept{OutputIterator}s and other iterator types
|
||||||
(e.g. \code{std::vector<bool>::iterator}, which uses a proxy
|
(e.g. \code{std::vector<bool>::iterator}, which uses a proxy
|
||||||
\code{reference}).}
|
\code{reference}).}
|
||||||
|
|
||||||
The defaults for the \code{iterator\_\-category},
|
The defaults for the \iteratorcategory{} and \differencetype{} are
|
||||||
and \code{difference\_\-type} are straightforward: they are the
|
straightforward: they are the respective types from the \code{Base}
|
||||||
respective types from the \code{Base} iterator. These work out well as
|
iterator. These work out well as the final parameters, because one usually wants
|
||||||
the final parameters, because one usually wants all of the
|
all of the capabilities supplied by the iterator being adapted, and it is
|
||||||
capabilities supplied by the iterator being adapted, and it is
|
|
||||||
difficult to provide more capabilities.
|
difficult to provide more capabilities.
|
||||||
|
|
||||||
The code used to select the appropriate defaults for the iterator's
|
The code used to select the appropriate defaults for the iterator's
|
||||||
@@ -807,10 +944,10 @@ Iterator Adaptor described earlier
|
|||||||
% When we reorganize the paper it may appear later. check this out.
|
% When we reorganize the paper it may appear later. check this out.
|
||||||
limits the category of its \code{Base} iterator to
|
limits the category of its \code{Base} iterator to
|
||||||
\stlconcept{InputIterator}, so the we'd only need to supply the
|
\stlconcept{InputIterator}, so the we'd only need to supply the
|
||||||
\code{value\_type}, \code{reference}, and \code{iterator\_category} if
|
\valuetype{}, \code{reference}, and \iteratorcategory\ if
|
||||||
the \code{Category} parameter didn't appear last. Iterators where the
|
the \code{Category} parameter didn't appear last. Iterators where the
|
||||||
\code{Base} type is not itself an iterator also act this way, since
|
\code{Base} type is not itself an iterator also act this way, since
|
||||||
there are no appropriate \code{iterator\_traits} from which to derive
|
there are no appropriate \iteratortraits\ from which to derive
|
||||||
the \code{Pointer} and \code{Reference} parameters.
|
the \code{Pointer} and \code{Reference} parameters.
|
||||||
|
|
||||||
\subsubsection{Named Template Parameters}
|
\subsubsection{Named Template Parameters}
|
||||||
@@ -831,11 +968,11 @@ an appropriately-named wrapper class for each parameter. For example:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Instead of passing the argument \code{Value} directly to
|
Instead of passing the argument \code{Value} directly to
|
||||||
\code{iterator\_\-adaptor} the user passes
|
\iteratoradaptor\ the user passes
|
||||||
\code{value\_type\_is<Value>}. The \code{iterator\_\-adaptor} has
|
\code{value\_type\_is<Value>}. The \iteratoradaptor\ has
|
||||||
five arguments for the associated types, each of which could be used
|
five arguments for the associated types, each of which could be used
|
||||||
to specify any of the actual parameters. The
|
to specify any of the actual parameters. The
|
||||||
\code{iterator\_\-adaptor} must deduce which argument is for which
|
\iteratoradaptor\ must deduce which argument is for which
|
||||||
parameter based on the \code{tag} inside the wrapper.
|
parameter based on the \code{tag} inside the wrapper.
|
||||||
|
|
||||||
First we take all of the parameters and place them in a
|
First we take all of the parameters and place them in a
|
||||||
@@ -864,7 +1001,7 @@ list using a template meta-program utility class named
|
|||||||
}
|
}
|
||||||
|
|
||||||
\noindent So, for example, to retrieve the argument for the
|
\noindent So, for example, to retrieve the argument for the
|
||||||
\code{value\_type} we write the following:
|
\valuetype\ we write the following:
|
||||||
|
|
||||||
{\footnotesize
|
{\footnotesize
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
@@ -882,7 +1019,7 @@ resolved is tailored to respect these dependencies.
|
|||||||
|
|
||||||
\subsection{Core Operators}
|
\subsection{Core Operators}
|
||||||
|
|
||||||
The core operators of the \code{iterator\_adaptor} are implemented by
|
The core operators of the \iteratoradaptor\ are implemented by
|
||||||
delegating the work to the policies class. Each core operator invokes
|
delegating the work to the policies class. Each core operator invokes
|
||||||
the appropriate policy function and passes in the base
|
the appropriate policy function and passes in the base
|
||||||
iterator. Sometimes extra type information is also passed in, as is
|
iterator. Sometimes extra type information is also passed in, as is
|
||||||
@@ -900,7 +1037,7 @@ the case with the \code{reference} type in the implementation of
|
|||||||
The binary operators of the iterator are implemented as free functions
|
The binary operators of the iterator are implemented as free functions
|
||||||
(not member functions) to allow both the left and right hand operands
|
(not member functions) to allow both the left and right hand operands
|
||||||
to be treated symmetrically. We use separate template parameters for
|
to be treated symmetrically. We use separate template parameters for
|
||||||
the two \code{iterator\_\-adaptor} arguments. This allows a single
|
the two \iteratoradaptor\ arguments. This allows a single
|
||||||
operator to implement all of the combinations of constant/mutable
|
operator to implement all of the combinations of constant/mutable
|
||||||
iterator interactions, avoiding the combinatorial explosion discussed
|
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
|
||||||
@@ -968,7 +1105,7 @@ the pointer to perform the usual member dereferencing. It also turns
|
|||||||
out to be what we need to make a conforming
|
out to be what we need to make a conforming
|
||||||
\stlconcept{InputIterator}. By making the return type of
|
\stlconcept{InputIterator}. By making the return type of
|
||||||
\code{operator->} a proxy containing an instance of the iterator's
|
\code{operator->} a proxy containing an instance of the iterator's
|
||||||
\code{value\_type}, we can eventually form a \code{const} pointer to
|
\valuetype{}, we can eventually form a \code{const} pointer to
|
||||||
the returned temporary:
|
the returned temporary:
|
||||||
|
|
||||||
{\footnotesize
|
{\footnotesize
|
||||||
@@ -1019,7 +1156,7 @@ iterator categories derived from the standard ones.
|
|||||||
The implementation of \code{operator[]} would be trivial except for
|
The implementation of \code{operator[]} would be trivial except for
|
||||||
the issue surrounding what the return type should be. As mentioned in
|
the issue surrounding what the return type should be. As mentioned in
|
||||||
\S\ref{sec:operator-bracket}, it would be dangerous to make the
|
\S\ref{sec:operator-bracket}, it would be dangerous to make the
|
||||||
\code{iterator\_adaptor} always return a reference for
|
\iteratoradaptor\ always return a reference for
|
||||||
\code{operator[]} for there are certain situations in which this can
|
\code{operator[]} for there are certain situations in which this can
|
||||||
cause run-time errors.
|
cause run-time errors.
|
||||||
|
|
||||||
@@ -1063,7 +1200,7 @@ dereference returns a reference to a data member of this temporary,
|
|||||||
which is destroyed before \code{operator[]} returns. The result is a
|
which is destroyed before \code{operator[]} returns. The result is a
|
||||||
dangling reference.
|
dangling reference.
|
||||||
|
|
||||||
Boost's \code{iterator\_adaptor} takes the safe route and returns the
|
Boost's \iteratoradaptor\ takes the safe route and returns the
|
||||||
result by-value. This meets the random access iterator requirements of
|
result by-value. This meets the random access iterator requirements of
|
||||||
the Standard, which only says that the return type must be
|
the Standard, which only says that the return type must be
|
||||||
``convertible to T'',
|
``convertible to T'',
|
||||||
@@ -1075,13 +1212,13 @@ the Standard, which only says that the return type must be
|
|||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
}
|
}
|
||||||
|
|
||||||
Under the current {C++} Standard, you cannot assign into the result of
|
Under the current \Cpp\ Standard, you cannot assign into the result of
|
||||||
\code{operator[]} applied to a generic random access iterator,
|
\code{operator[]} applied to a generic random access iterator,
|
||||||
but instead must write \code{*(i + n) = x}.
|
but instead must write \code{*(i + 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 to make the
|
\iteratortraits\ 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
|
||||||
@@ -1101,14 +1238,14 @@ problem, but of course that will take some time to gain acceptance.
|
|||||||
\section{Conclusion}
|
\section{Conclusion}
|
||||||
|
|
||||||
Constructing iterators and iterator adaptors is a common task for
|
Constructing iterators and iterator adaptors is a common task for
|
||||||
modern C++ programming. Despite the conceptual simplicity of most
|
modern \Cpp\ programming. Despite the conceptual simplicity of most
|
||||||
iterators, implementing {C++} Standard conforming iterators requires a
|
iterators, implementing \Cpp\ Standard conforming iterators requires a
|
||||||
non-trivial amount of code, some of which is challenging to get right
|
non-trivial amount of code, some of which is challenging to get right
|
||||||
and a lot of which is tedious. The \code{iterator\_adaptor} class that
|
and a lot of which is tedious. The \iteratoradaptor\ class that
|
||||||
we've presented solves these problem by providing a mechanism
|
we've presented solves these problem by providing a mechanism
|
||||||
by which the user provides a minimal specification (by way of the
|
by which the user provides a minimal specification (by way of the
|
||||||
policies class) for the iterator, and then the
|
policies class) for the iterator, and then the
|
||||||
\code{iterator\_\-adaptor} takes care of most of the implementation
|
\iteratoradaptor\ takes care of most of the implementation
|
||||||
details.
|
details.
|
||||||
|
|
||||||
Taking a step back, the design approach was to create a canonical
|
Taking a step back, the design approach was to create a canonical
|
||||||
|
Reference in New Issue
Block a user