edits. What can I say?

[SVN r10992]
This commit is contained in:
Dave Abrahams
2001-09-02 04:42:43 +00:00
parent 89107738b3
commit 506334c120

View File

@@ -115,8 +115,8 @@ on other iterators (adapted iterators) and generators of new iterator
families (iterator adaptors). The Iterator Adaptor Library is an families (iterator adaptors). The Iterator Adaptor Library is an
example of policy-based design and employs template example of policy-based design and employs template
meta-programming. We also present the Policy Adapter implementation meta-programming. We also present the Policy Adapter implementation
pattern, a strategy used by the library that can also be used to pattern, a strategy which can also be used to generate new
generate new representatives of other abstract Concept families. representatives of other abstract Concept families.
\end{abstract} \end{abstract}
@@ -152,14 +152,17 @@ Concept, iterators can be both efficient and convenient to use.
The \Cpp\ Standard Library contains a wide variety of useful The \Cpp\ Standard Library contains a wide variety of useful
iterators. Every one of the standard containers comes with constant iterators. Every one of the standard containers comes with constant
and mutable iterators (iterators that point to constant objects and and mutable iterators\footnote{The term \emph{mutable iterator} refers
iterators that point to objects that can be changed or assigned to), to iterators over objects that can be changed by assigning to the
and also \code{reverse\_} versions of the iterators that traverse the dereferenced iterator, while \emph{constant iterator} refers to
iterators over objects that cannot be modified}, and also
\code{reverse\_} versions of those same iterators which traverse the
container in the opposite direction. The Standard also supplies container in the opposite direction. The Standard also supplies
\code{istream\_\-iterator} and \code{ostream\_\-iterator} for reading \code{istream\_\-iterator} and \code{ostream\_\-iterator} for reading
from and writing to streams, \code{insert\_iterator} and from and writing to streams, \code{insert\_iterator},
\code{back\_insert\_iterator} for inserting elements in containers, \code{front\_insert\_iterator} and \code{back\_insert\_iterator} for
and \code{raw\_\-storage\_\-iterator} for initializing raw inserting elements into containers, and
\code{raw\_\-storage\_\-iterator} for initializing raw
memory~\cite{iso98:_cpp_final_draft_standard}. memory~\cite{iso98:_cpp_final_draft_standard}.
Despite the many iterators supplied by the Standard Library, many Despite the many iterators supplied by the Standard Library, many
@@ -169,7 +172,7 @@ several of these, for example
\code{line\_iterator}~\cite{austern99:_gener_progr_stl} \code{line\_iterator}~\cite{austern99:_gener_progr_stl}
\code{Constant\_iterator}~\cite{koenig97:_rumin_cpp}. The iterator \code{Constant\_iterator}~\cite{koenig97:_rumin_cpp}. The iterator
abstraction is so powerful, however, that we expect programmers will abstraction is so powerful, however, that we expect programmers will
always invent new iterator types. always need to invent new iterator types.
\subsection{Adaptors} \subsection{Adaptors}
@@ -191,8 +194,8 @@ bounds-checking to an existing iterator.
Library~\cite{TMPW00:Weiser}, which adapts containers, are themselves Library~\cite{TMPW00:Weiser}, which adapts containers, are themselves
adaptors over the underlying iterators. adaptors over the underlying iterators.
\item smart iterators~\cite{becker98:_smart_iterators}, \item smart iterators~\cite{becker98:_smart_iterators}
which adapt an iterator's dereferencing behavior by applying a adapt an iterator's dereferencing behavior by applying a
function object to the object being referenced and returning the function object to the object being referenced and returning the
result. result.
@@ -235,7 +238,7 @@ have followed the lead of the standard library, which provides a
\code{base()} function to access the underlying iterator object of a \code{base()} function to access the underlying iterator object of a
\reverseiterator\ adaptor.} \reverseiterator\ adaptor.}
\subsection{Core Elements of the Concept} \subsection{Core Elements of the Iterator Concept}
The first step in designing such a generalized Model is to identify The first step in designing such a generalized Model is to identify
the core elements of its interface. We have identified the following the core elements of its interface. We have identified the following
@@ -286,8 +289,9 @@ were quickly implemented using \iteratoradaptor{}:\begin{itemize}
smart pointers and applies an extra level of dereferencing. smart pointers and applies an extra level of dereferencing.
\item Reverse Iterator Adaptor, which inverts the direction of a \item Reverse Iterator Adaptor, which inverts the direction of a
\code{Base} iterator's motion. \code{Base} iterator's motion, while allowing adapted constant and
% say something about how this one is better than the std one? mutable iterators to interact in the expected ways. We will discuss
this further in Section \ref{sec:constant-mutable-iterations}.
\item Transform Iterator Adaptor, which applies a user-defined \item Transform Iterator Adaptor, which applies a user-defined
function object to the underlying values when dereferenced. We will function object to the underlying values when dereferenced. We will
@@ -328,7 +332,7 @@ and delegating functions and by taking care of the complex details of
iterator implementation. iterator implementation.
The central design feature of \iteratoradaptor\ is parameterization by The central design feature of \iteratoradaptor\ is parameterization by
an iterator policies class. The policies class is the primary a policies class. The policies class is the primary
communication mechanism between the iterator implementer and the communication mechanism between the iterator implementer and the
\iteratoradaptor{}; it specifies how the new iterator type \iteratoradaptor{}; it specifies how the new iterator type
behaves. Unlike the policy classes behaves. Unlike the policy classes
@@ -339,12 +343,18 @@ implementation.
\subsection{Iterator Policies Class} \subsection{Iterator Policies Class}
\label{sec:iterator-policies-class} \label{sec:iterator-policies-class}
The following example shows how to implement the policies class for a transform The following example shows how to implement the policies class for a
iterator adaptor: an iterator that applies some function to the value returned transform iterator adaptor: an iterator that applies some function to
by dereferencing the base iterator. The the value returned by dereferencing the base iterator. The
\code{transform\_\-iterator\_\-policies} class is templated on the function \code{transform\_\-iterator\_\-policies} class is templated on the
object type, and a function object is stored as a data member of the policies function object type, and a function object is stored as a data member
class. When adapting an underlying iterator, it is easiest to store any extra state of the policies class.\footnote{We might instead have composed the
underlying iterator and the function object into a single \code{Base}
type, but that would have been much more work because so many useful
defaults are provided when the \code{Base} type is itself an
iterator.}
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 \iteratoradaptor\ 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.
@@ -357,11 +367,12 @@ 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. Because the
type is a template parameter to allow this policy class to be used iterator type is a template parameter of the \code{dereference()}
with any base iterator type.\footnote{The term``\code{BaseIterator}'' function, the same concrete policies class can be used with any base
here is meant to denote that the \code{Base} type is expected to be an iterator type, which greatly simplifies adaptation.\footnote{The
iterator.} 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}
@@ -460,10 +471,10 @@ namespace boost {
\label{sec:iter-type-generator} \label{sec:iter-type-generator}
In Section~\ref{sec:iterator-policies-class} we showed how to create In Section~\ref{sec:iterator-policies-class} we showed how to create
the policy class for the transform iterator, so the next step is to the policy class for the transform iterator; the next step is to use
use the \iteratoradaptor\ template to construct the actual iterator the \iteratoradaptor\ template to construct the actual iterator
type. The best way to package the construction of the transform type. The best way to package the construction of the transform
iterator is to create a \emph{type generator}, which is a class iterator is to create a \emph{type generator}: a class
template whose sole purpose is to simplify the instantiation of some template whose sole purpose is to simplify the instantiation of some
other complicated class template. It fulfills the same need as a other complicated class template. It fulfills the same need as a
template typedef would if that were part of the \Cpp\ language. The template typedef would if that were part of the \Cpp\ language. The
@@ -486,11 +497,11 @@ shows the type generator for the transform iterator.
\end{verbatim} \end{verbatim}
} }
We use \iteratoradaptor\ to define the transform iterator type We use \iteratoradaptor\ to define the transform iterator type as a
as a nested \code{typedef} inside the nested \code{typedef} inside the
\code{transform\_\-iterator\_\-generator} class. The first parameter \code{transform\_\-iterator\_\-generator} class. The first parameter
to \iteratoradaptor\ is the base iterator type and the second to \iteratoradaptor\ is the base iterator type and the second is the
is the policies class. The remaining parameters specify the iterators policies class. The remaining parameters specify the iterator's
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}.
@@ -503,11 +514,11 @@ the \code{pointer} type defaults to \code{value\_type*} and the
\differencetype{} defaults to the \differencetype{} 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} class template
from \iteratoradaptor\ (as an alternative to using the which is derived from \iteratoradaptor\, instead of 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, while in this case the return type would be
\iteratoradaptor\ and not \code{transform\_\-iterator}. \iteratoradaptor\ and not \code{transform\_\-iterator}.
%It %It
@@ -532,14 +543,15 @@ they would have to separately construct a policies object and then the
iterator object. We therefore recommend that iterator implementers iterator object. We therefore recommend that iterator implementers
create an \emph{object generator} function for their iterator. The create an \emph{object generator} function for their iterator. The
following is the generator function for the transform iterator following is the generator function for the transform iterator
adaptor.\footnote{ adaptor.\footnote{ Although there is precedent in the standard for
There is precedent in the standard for calling such calling such an object generator, simply
an object generator, simply ``\code{transform\_iterator()}'' ``\code{transform\_iterator()}'' (e.g. \code{std::back\_inserter}),
(e.g. \code{std::back\_inserter}), but also for the more explicit the standard also uses the more explicit ``\code{make\_}'' prefix
\code{make\_} prefix (e.g. \code{std::make\_pair()}) and occasionally (e.g. \code{std::make\_pair()}) and occasionally also uses the simple
for using the simple name for the adaptor type itself name for the iterator type itself
(e.g. \code{std::reverse\_iterator}). In the end, the authors decided (e.g. \code{std::reverse\_iterator}). In the end, the authors felt
that explicit was better than implicit. } that explicit was better than implicit and decided to use the
``\code{make\_}'' prefix for object generators. }
{\footnotesize {\footnotesize
\begin{verbatim} \begin{verbatim}
@@ -714,7 +726,7 @@ iterator takes its \valuetype\ from the \code{Base}
iterator's \iteratortraits{}. 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 \valuetype\ will just be \code{T}.Perhaps the \valuetype\ will just be \code{T}. Perhaps
strangely, a constant iterator's \valuetype\ 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
@@ -812,8 +824,7 @@ associated types used to look something like this:
Unfortunately, this strategy can only take us so far. It turns out Unfortunately, this strategy can only take us so far. It turns out
that there are plenty of iterators which don't fit neatly into the that there are plenty of iterators which don't fit neatly into the
system for ordering defaults. For example, the specialized Transform system for ordering defaults. For example, the specialized Transform
Iterator Adaptor described earlier Iterator Adaptor described in Section~\ref{sec:iterator-policies-class}
% 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
\valuetype{}, \code{reference}, and \iteratorcategory\ if \valuetype{}, \code{reference}, and \iteratorcategory\ if
@@ -840,7 +851,7 @@ 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
\iteratoradaptor\ the user passes \iteratoradaptor\ the user can pass
\code{value\_type\_is<Value>}. The \iteratoradaptor\ 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
@@ -967,7 +978,9 @@ kinds of iterators should propagate the ability to interact. For
example, a reverse iterator adaptor applied to \code{C::iterator} and example, a reverse iterator adaptor applied to \code{C::iterator} and
\code{C::const\_iterator} should result in mutable and constant \code{C::const\_iterator} should result in mutable and constant
reverse iterator types that have the same ability to interact as the reverse iterator types that have the same ability to interact as the
\code{Base} iterators do. \code{Base} iterators do. The \reverseiterator{} adaptor supplied by
the Iterator Adaptor Library have this ability, although those
supplied by the \Cpp\ standard library do not.
The iterator adaptor binary operators are implemented using function The iterator adaptor binary operators are implemented using function
templates (as shown in the previous Subsection). This allows the same templates (as shown in the previous Subsection). This allows the same
@@ -1117,13 +1130,13 @@ dangling reference.
The \Cpp\ 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
opens up the possibility of returning by-balue from \code{operator[]} opens up the possibility of returning by-value from \code{operator[]}
instead of by-reference, and thereby avoiding the above problem. This instead of by-reference, thereby avoiding the above problem. This
approach, though safer, has the disadvantage of being a less approach, though safer, has the disadvantage of being a less
orthogonal design since \code{operator*} is required to return the orthogonal design since \code{operator*} is required to return the
exact type \code{T\&}, and one might think that \code{operator[]} and exact type \code{T\&}, and one might think that \code{operator[]} and
\code{operator*} should be same in this respect. The \Cpp\ Standards \code{operator*} should be same in this respect. The \Cpp\ Standards
Committee is currently debating as to whether the random access Committee is currently debating the question of whether the random access
iterator requirements should be changed. iterator requirements should be changed.
Boost's \iteratoradaptor\ takes the safe route and returns the result Boost's \iteratoradaptor\ takes the safe route and returns the result
@@ -1143,9 +1156,11 @@ Under the current \Cpp\ Standard, you cannot assign into the result of
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 \iteratortraits\
\iteratortraits\ does not provide enough information to make the does not provide enough information to make the choice. The proposal
choice. in~\cite{siek01:_improved_iter_cat} would solve this problem, but of
course that will take some time to gain acceptance.
% Jeremy: I didn't agree with this part, so commented it out % Jeremy: I didn't agree with this part, so commented it out
% temporarily. I think an iterator which can return by-reference for % temporarily. I think an iterator which can return by-reference for
@@ -1157,10 +1172,6 @@ choice.
% iterator would either return by-value for both \code{operator*} and % iterator would either return by-value for both \code{operator*} and
% \code{operator[]} or return by-reference for both. % \code{operator[]} or return by-reference for both.
The proposal in~\cite{siek01:_improved_iter_cat} would solve this
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