mirror of
https://github.com/boostorg/utility.git
synced 2025-07-30 21:07:27 +02:00
total reorg. Whew!
[SVN r10989]
This commit is contained in:
@ -205,8 +205,17 @@ in which a variety of adaptor types are enumerated.
|
|||||||
|
|
||||||
\section{The Boost Iterator Adaptor Library}
|
\section{The Boost Iterator Adaptor Library}
|
||||||
|
|
||||||
% Do we need a section body?
|
% We need an intro here (do we?), but I don't think the text below
|
||||||
In this section, we present the Boost Iterator Adaptor Library.
|
% fits in. Suggestions?
|
||||||
|
|
||||||
|
% For an iterator to be usable with the Standard algorithms (and other
|
||||||
|
% generic algorithms), 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. The Boost Iterator
|
||||||
|
% Adaptor Library addresses these problems.
|
||||||
|
|
||||||
\subsection{Overall Design}
|
\subsection{Overall Design}
|
||||||
|
|
||||||
@ -222,7 +231,7 @@ the use of inheritance. We have followed the lead of the standard
|
|||||||
library, which provides a \code{base()} function to access the
|
library, which provides a \code{base()} function to access the
|
||||||
underlying iterator object of a \reverseiterator\ adaptor.}
|
underlying iterator object of a \reverseiterator\ adaptor.}
|
||||||
|
|
||||||
\subsubsection{Core Elements of the Concept}
|
\subsection{Core Elements of the 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
|
||||||
@ -247,16 +256,16 @@ these: as traditional and also as \emph{named} template parameters
|
|||||||
(described below), and uses a system of smart defaults which in most
|
(described below), and uses a system of smart defaults which in most
|
||||||
cases reduces the number of these types that must be specified.
|
cases reduces the number of these types that must be specified.
|
||||||
|
|
||||||
\subsubsection{From Building Models to Building Adaptors}
|
\subsection{From Building Models to Building Adaptors}
|
||||||
|
|
||||||
A generalized iterator is useful, but a generalized iterator
|
A generalized iterator is useful, but a generalized iterator
|
||||||
\emph{adaptor} would be even more useful. One could then build
|
\emph{adaptor} would be even more useful. One could then build
|
||||||
specialized adaptors to generate new families of iterator instances
|
specialized adaptors to generate new families of iterator instances
|
||||||
based on existing iterators. In the Boost Iterator Adaptor Library,
|
based on existing iterators. In the Boost Iterator Adaptor Library,
|
||||||
the role of adaptor is also played by the \iteratoradaptor\ class
|
the \iteratoradaptor\ class template plays the roles of both Adaptor
|
||||||
template. The behaviors of \iteratoradaptor{} instances are supplied
|
and Model. The behaviors of \iteratoradaptor{} instances are supplied
|
||||||
through a Policies class~\cite{alexandrescu01:_modern_cpp_design}
|
through a policies class~\cite{alexandrescu01:_modern_cpp_design}
|
||||||
which allows allows users to specialize adaptation. They go beyond
|
which allows allows users to specialize adaptation. Users go beyond
|
||||||
generating new iterator types to easily generating new iterator
|
generating new iterator types to easily generating new iterator
|
||||||
adaptor families.
|
adaptor families.
|
||||||
|
|
||||||
@ -277,8 +286,16 @@ show how this adaptor is implemented below.
|
|||||||
Iterator Adaptor except that when dereferenced it returns by-reference
|
Iterator Adaptor except that when dereferenced it returns by-reference
|
||||||
instead of by-value.
|
instead of by-value.
|
||||||
|
|
||||||
\item Filter Iterator Adaptor, which view of an iterator range in
|
\item Filter Iterator Adaptor, which provides a view of an iterator
|
||||||
which some elements of the range are skipped over.
|
range in which some elements of the underlying range are skipped.
|
||||||
|
|
||||||
|
\item Counting Iterator Adaptor, which adapts any incrementable type
|
||||||
|
(e.g. integers, iterators) so that incrementing/decrementing the
|
||||||
|
adapted iterator and dereferencing it produces successive values of
|
||||||
|
the \code{Base} type.
|
||||||
|
|
||||||
|
\item Function Output Iterator Adaptor, which makes it easier to
|
||||||
|
create custom output iterators.
|
||||||
|
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
|
|
||||||
@ -288,222 +305,6 @@ permutation to a \stlconcept{RandomAccessIterator}, and a strided
|
|||||||
adaptor, which adapts a \stlconcept{RandomAccessIterator} by
|
adaptor, which adapts a \stlconcept{RandomAccessIterator} by
|
||||||
multiplying its unit of motion by a constant factor.
|
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}
|
|
||||||
|
|
||||||
Perhaps the most obvious reason that implementing an iterator can
|
|
||||||
be tedious is that there are lots of redundant operators. That is,
|
|
||||||
there are many operators that can be trivially defined in terms of
|
|
||||||
other operators. For example, the postfix \code{operator++(int)} is often best
|
|
||||||
implemented in terms of prefix \code{operator++()} as shown below.
|
|
||||||
|
|
||||||
{\footnotesize
|
|
||||||
\begin{verbatim}
|
|
||||||
class iter {
|
|
||||||
// ...
|
|
||||||
iter& operator++() { /* ... */ return *this; }
|
|
||||||
iter operator++(int) { iter tmp(*this); ++*this; return tmp; }
|
|
||||||
};
|
|
||||||
\end{verbatim}
|
|
||||||
}
|
|
||||||
|
|
||||||
For a full \stlconcept{RandomAccessIterator}, there are a total of 17
|
|
||||||
operators. 7 of the operators are fundamental while the other 10 are
|
|
||||||
redundant.
|
|
||||||
|
|
||||||
% 7 core operations
|
|
||||||
% 10 derived operations
|
|
||||||
|
|
||||||
% \code{operator->}
|
|
||||||
% \code{operator[]}
|
|
||||||
% \code{operator++(int)},
|
|
||||||
% \code{operator--(int)},
|
|
||||||
% \code{operator-=},
|
|
||||||
% \code{operator+},
|
|
||||||
% \code{operator!=},
|
|
||||||
% \code{operator>},
|
|
||||||
% \code{operator<=},
|
|
||||||
% \code{operator>=}
|
|
||||||
|
|
||||||
|
|
||||||
\subsection{Delegation of Operators and Type Definitions}
|
|
||||||
|
|
||||||
An iterator adaptor used to adapt an underlying iterator type often
|
|
||||||
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
|
|
||||||
is typically implemented with delegating functions.\footnote{Although
|
|
||||||
one might normally consider parametrized inheritance for cases where
|
|
||||||
many functions must be forwarded, that is not possible for a
|
|
||||||
generalized iterator adaptor because the underlying type may be a
|
|
||||||
pointer} The following example shows an excerpt from an
|
|
||||||
\code{indirect\_iterator} adaptor, which takes an iterator over
|
|
||||||
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
|
|
||||||
\begin{verbatim}
|
|
||||||
template <class Base> class indirect_iterator {
|
|
||||||
public:
|
|
||||||
// Adapt the meaning of dereference
|
|
||||||
reference operator*() const {
|
|
||||||
return **iter; // dereference twice
|
|
||||||
}
|
|
||||||
// a ``redundant'' operator
|
|
||||||
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.
|
|
||||||
indirect_iterator& operator++() { ++iter; return *this; }
|
|
||||||
indirect_iterator& operator--() { --iter; return *this; }
|
|
||||||
// delegate for all the other operators...
|
|
||||||
private:
|
|
||||||
Base iter;
|
|
||||||
};
|
|
||||||
\end{verbatim}
|
|
||||||
}
|
|
||||||
|
|
||||||
% I think it would be better to use reverse_iterator as an example
|
|
||||||
% here, because it delegates more types than indirect_iterator does.
|
|
||||||
% But reverse_iterator doesn't delegate many operators... it changes
|
|
||||||
% the meaning of all of them. I wonder if there's a good example
|
|
||||||
% for both operators and typedefs.
|
|
||||||
A standard-conforming iterator must either come with a specialization
|
|
||||||
of \code{std::iterator\_\-traits<>} or it must define five nested
|
|
||||||
types: \valuetype{}, \code{reference}, \code{pointer},
|
|
||||||
\differencetype{}, and \iteratorcategory{}. 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 Implementation Complexities}
|
|
||||||
|
|
||||||
In addition to the tedious aspects of iterator implementation, there
|
|
||||||
are some complexities that trip up even the most experienced of
|
|
||||||
programmers. Ideally, an iterator implementer should not have to worry
|
|
||||||
about these details.
|
|
||||||
|
|
||||||
\subsubsection{Constant/Mutable Iterator Interactions}
|
|
||||||
\label{sec:constant-mutable-iterations}
|
|
||||||
|
|
||||||
Iterators over containers and other sequences of stored objects
|
|
||||||
usually come in pairs: a constant iterator type and a mutable iterator
|
|
||||||
type. It is desirable to allow the constant and mutable iterators to
|
|
||||||
interoperate through comparison and
|
|
||||||
subtraction. For example, suppose
|
|
||||||
that you are implementing a container type \code{C}. Then you ought to
|
|
||||||
define the following four versions of \code{operator==}, along with
|
|
||||||
corresponding versions of \code{operator!=}, and (for
|
|
||||||
\stlconcept{RandomAccessIterator}), operators \code{<}, \code{>},
|
|
||||||
\code{<=}, \code{>=}, and \code{-}.
|
|
||||||
|
|
||||||
{\footnotesize
|
|
||||||
\begin{verbatim}
|
|
||||||
bool operator==(const C::iterator& x, const C::iterator& y);
|
|
||||||
bool operator==(const C::const_iterator& x, const C::iterator& y);
|
|
||||||
bool operator==(const C::iterator& x, const C::const_iterator& y);
|
|
||||||
bool operator==(const C::const_iterator& x, const C::const_iterator& y);
|
|
||||||
\end{verbatim}
|
|
||||||
}
|
|
||||||
|
|
||||||
Implementers often forget to define the operators for constant/mutable
|
|
||||||
iterator interaction. In addition, iterator adaptors applied to these
|
|
||||||
kinds of iterators should propagate the ability to interact. For
|
|
||||||
example, a reverse iterator adaptor applied to \code{C::iterator} and
|
|
||||||
\code{C::const\_iterator} should result in mutable and constant reverse iterator types that
|
|
||||||
have the same ability to interact as the \code{Base} iterators do.
|
|
||||||
|
|
||||||
\subsubsection{Constant/Mutable Iterator Code Duplication}
|
|
||||||
|
|
||||||
% Is this section really worthwhile? It was confusing to read until I
|
|
||||||
% finally figured out what you were driving at. Who makes this conceptual mistake?
|
|
||||||
% It may not be worthwhile... though I've seen other grad students make
|
|
||||||
% this mistake, and the TMPW2000 VTL paper contains this mistake.
|
|
||||||
|
|
||||||
The implementations of the constant and mutable versions of an
|
|
||||||
iterator typically differ only in their \code{reference} and
|
|
||||||
\code{pointer} types. Therefore it is desirable to merge the two
|
|
||||||
iterator classes into a single class template with the
|
|
||||||
\code{reference} and \code{pointer} types as template parameters.
|
|
||||||
|
|
||||||
Some care must be taken when merging the constant and mutable
|
|
||||||
iterators. One common mistake is that the programmer will confuse the
|
|
||||||
ideas of a \code{const} iterator object and a \emph{constant
|
|
||||||
iterator}. Such a misunderstanding can, for example, lead to an
|
|
||||||
iterator class template that has two versions of \code{operator*}, one
|
|
||||||
that is a \code{const} member function and one that is not.
|
|
||||||
|
|
||||||
{\footnotesize
|
|
||||||
\begin{verbatim}
|
|
||||||
// this is a mistake
|
|
||||||
reference operator*();
|
|
||||||
const_reference operator*() const;
|
|
||||||
\end{verbatim}
|
|
||||||
}
|
|
||||||
|
|
||||||
There should be only one \code{operator*} that returns the
|
|
||||||
\code{reference} type and the member function should be \code{const} since
|
|
||||||
dereferencing an iterator does not change the state of the iterator
|
|
||||||
object itself (unlike \code{operator++}).
|
|
||||||
|
|
||||||
{\footnotesize
|
|
||||||
\begin{verbatim}
|
|
||||||
// this is right
|
|
||||||
reference operator*() const;
|
|
||||||
\end{verbatim}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
\subsubsection{Input Iterators and \code{operator->}}
|
|
||||||
\label{sec:operator-arrow}
|
|
||||||
|
|
||||||
When creating an iterator adaptor that produces an
|
|
||||||
\stlconcept{InputIterator} some extra care must be taken in the
|
|
||||||
implementation of \code{operator->}. Remember that an input iterator
|
|
||||||
need not iterate over stored objects: it can manufacture new objects
|
|
||||||
when it is dereferenced as is the case for
|
|
||||||
\code{std::istream\_iterator}. If the iterator's \valuetype\ is
|
|
||||||
of class type, we need to support \code{operator->}. Since the result
|
|
||||||
of using \code{operator->} must produce a true pointer even when
|
|
||||||
dereferencing the iterator does not yield a true reference type, we
|
|
||||||
need a \code{const} lvalue to which a pointer can be formed. In
|
|
||||||
\S\ref{sec:operator-arrow} we show how this can be accomplished.
|
|
||||||
|
|
||||||
|
|
||||||
\subsubsection{The Return Type of \code{operator[]} for Adaptors}
|
|
||||||
\label{sec:operator-bracket}
|
|
||||||
|
|
||||||
The \Cpp\ 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 \Cpp\ 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 \iteratoradaptor\ Class Template}
|
\section{The Boost \iteratoradaptor\ Class Template}
|
||||||
|
|
||||||
The \iteratoradaptor\ class template simplifies the creation
|
The \iteratoradaptor\ class template simplifies the creation
|
||||||
@ -511,11 +312,11 @@ 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 \iteratoradaptor\ is the
|
The central design feature of \iteratoradaptor\ is
|
||||||
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 \iteratoradaptor{}; 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 behaves. 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
|
||||||
implementation.
|
implementation.
|
||||||
@ -782,6 +583,255 @@ negate the numbers over which it iterates.
|
|||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
\section{The Policy Adaptor Design Pattern}
|
||||||
|
|
||||||
|
The Iterator Adaptor Library illustrates how a generalized Model
|
||||||
|
(\iteratoradaptor{}) of a Concept family (iterators) combined with
|
||||||
|
default policy delegation allows users to easily build new Models and
|
||||||
|
behavioral adaptors for existing Models. We can capture this strategy
|
||||||
|
in the Policy Adaptor design pattern:\footnote{This is not quite the
|
||||||
|
same as the Policy Class pattern which has been discussed previously
|
||||||
|
in the literature~\cite{alexandrescu01:_modern_cpp_design}. The
|
||||||
|
construction of an adaptor which can easily transforms existing Models
|
||||||
|
into new ones is the key difference}\begin{itemize}
|
||||||
|
|
||||||
|
% Jeremy, can we get a numbered list here?
|
||||||
|
\item First, identify the core elements of the Adaptor Concept's
|
||||||
|
public interface. In our case, the Adaptor Concept is Iterator.
|
||||||
|
|
||||||
|
\item then, encapsulate core elements of the Concept family in a
|
||||||
|
Policies Concept.
|
||||||
|
|
||||||
|
\item Write a default policies class which delegates behavior to the
|
||||||
|
public interface of the Adaptor Concept. This is the mechanism that
|
||||||
|
supplies default adaptation behavior.
|
||||||
|
|
||||||
|
\item build an Adaptor class template parameterized on Policies. The
|
||||||
|
Adaptor should be a generalized model of the Adaptor Concept,
|
||||||
|
providing the public interface, but delegating functionality to the
|
||||||
|
policies class.
|
||||||
|
|
||||||
|
\item Store a member of the Policies parameter in the Adaptor
|
||||||
|
template so that users can store additional data while taking
|
||||||
|
advantage of default behavior delegation.
|
||||||
|
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
While the This pattern has not yet been widely tested for
|
||||||
|
applicability, we believe it will be useful for modelling any Concept
|
||||||
|
which varies along several axes and contains significant
|
||||||
|
redundancy.
|
||||||
|
|
||||||
|
% In addition, large number of iterator adaptors are now in use:
|
||||||
|
% iterators that that conforms to the Conceptual
|
||||||
|
% requirements of its iterator category
|
||||||
|
|
||||||
|
|
||||||
|
\section{The Iterator Implementation Generator}
|
||||||
|
|
||||||
|
\subsection{Redundant Operators}
|
||||||
|
|
||||||
|
Perhaps the most obvious reason that implementing an iterator can
|
||||||
|
be tedious is that there are lots of redundant operators. That is,
|
||||||
|
there are many operators that can be trivially defined in terms of
|
||||||
|
other operators. For example, the postfix \code{operator++(int)} is often best
|
||||||
|
implemented in terms of prefix \code{operator++()} as shown below.
|
||||||
|
|
||||||
|
{\footnotesize
|
||||||
|
\begin{verbatim}
|
||||||
|
class iter {
|
||||||
|
// ...
|
||||||
|
iter& operator++() { /* ... */ return *this; }
|
||||||
|
iter operator++(int) { iter tmp(*this); ++*this; return tmp; }
|
||||||
|
};
|
||||||
|
\end{verbatim}
|
||||||
|
}
|
||||||
|
|
||||||
|
For a full \stlconcept{RandomAccessIterator}, there are a total of 17
|
||||||
|
operators. 7 of the operators are fundamental while the other 10 are
|
||||||
|
redundant.
|
||||||
|
|
||||||
|
% 7 core operations
|
||||||
|
% 10 derived operations
|
||||||
|
|
||||||
|
% \code{operator->}
|
||||||
|
% \code{operator[]}
|
||||||
|
% \code{operator++(int)},
|
||||||
|
% \code{operator--(int)},
|
||||||
|
% \code{operator-=},
|
||||||
|
% \code{operator+},
|
||||||
|
% \code{operator!=},
|
||||||
|
% \code{operator>},
|
||||||
|
% \code{operator<=},
|
||||||
|
% \code{operator>=}
|
||||||
|
|
||||||
|
|
||||||
|
\subsection{Delegation of Operators and Type Definitions}
|
||||||
|
|
||||||
|
An iterator adaptor used to adapt an underlying iterator type often
|
||||||
|
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
|
||||||
|
is typically implemented with delegating functions.\footnote{Although
|
||||||
|
one might normally consider parametrized inheritance for cases where
|
||||||
|
many functions must be forwarded, that is not possible for a
|
||||||
|
generalized iterator adaptor because the underlying type may be a
|
||||||
|
pointer} The following example shows an excerpt from an
|
||||||
|
\code{indirect\_iterator} adaptor, which takes an iterator over
|
||||||
|
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
|
||||||
|
\begin{verbatim}
|
||||||
|
template <class Base> class indirect_iterator {
|
||||||
|
public:
|
||||||
|
// Adapt the meaning of dereference
|
||||||
|
reference operator*() const {
|
||||||
|
return **iter; // dereference twice
|
||||||
|
}
|
||||||
|
// a ``redundant'' operator
|
||||||
|
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.
|
||||||
|
indirect_iterator& operator++() { ++iter; return *this; }
|
||||||
|
indirect_iterator& operator--() { --iter; return *this; }
|
||||||
|
// delegate for all the other operators...
|
||||||
|
private:
|
||||||
|
Base iter;
|
||||||
|
};
|
||||||
|
\end{verbatim}
|
||||||
|
}
|
||||||
|
|
||||||
|
% I think it would be better to use reverse_iterator as an example
|
||||||
|
% here, because it delegates more types than indirect_iterator does.
|
||||||
|
% But reverse_iterator doesn't delegate many operators... it changes
|
||||||
|
% the meaning of all of them. I wonder if there's a good example
|
||||||
|
% for both operators and typedefs.
|
||||||
|
A standard-conforming iterator must either come with a specialization
|
||||||
|
of \code{std::iterator\_\-traits<>} or it must define five nested
|
||||||
|
types: \valuetype{}, \code{reference}, \code{pointer},
|
||||||
|
\differencetype{}, and \iteratorcategory{}. 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 Implementation Complexities}
|
||||||
|
|
||||||
|
In addition to the tedious aspects of iterator implementation, there
|
||||||
|
are some complexities that trip up even the most experienced of
|
||||||
|
programmers. Ideally, an iterator implementer should not have to worry
|
||||||
|
about these details.
|
||||||
|
|
||||||
|
\subsubsection{Constant/Mutable Iterator Interactions}
|
||||||
|
\label{sec:constant-mutable-iterations}
|
||||||
|
|
||||||
|
Iterators over containers and other sequences of stored objects
|
||||||
|
usually come in pairs: a constant iterator type and a mutable iterator
|
||||||
|
type. It is desirable to allow the constant and mutable iterators to
|
||||||
|
interoperate through comparison and
|
||||||
|
subtraction. For example, suppose
|
||||||
|
that you are implementing a container type \code{C}. Then you ought to
|
||||||
|
define the following four versions of \code{operator==}, along with
|
||||||
|
corresponding versions of \code{operator!=}, and (for
|
||||||
|
\stlconcept{RandomAccessIterator}), operators \code{<}, \code{>},
|
||||||
|
\code{<=}, \code{>=}, and \code{-}.
|
||||||
|
|
||||||
|
{\footnotesize
|
||||||
|
\begin{verbatim}
|
||||||
|
bool operator==(const C::iterator& x, const C::iterator& y);
|
||||||
|
bool operator==(const C::const_iterator& x, const C::iterator& y);
|
||||||
|
bool operator==(const C::iterator& x, const C::const_iterator& y);
|
||||||
|
bool operator==(const C::const_iterator& x, const C::const_iterator& y);
|
||||||
|
\end{verbatim}
|
||||||
|
}
|
||||||
|
|
||||||
|
Implementers often forget to define the operators for constant/mutable
|
||||||
|
iterator interaction. In addition, iterator adaptors applied to these
|
||||||
|
kinds of iterators should propagate the ability to interact. For
|
||||||
|
example, a reverse iterator adaptor applied to \code{C::iterator} and
|
||||||
|
\code{C::const\_iterator} should result in mutable and constant reverse iterator types that
|
||||||
|
have the same ability to interact as the \code{Base} iterators do.
|
||||||
|
|
||||||
|
\subsubsection{Constant/Mutable Iterator Code Duplication}
|
||||||
|
|
||||||
|
% Is this section really worthwhile? It was confusing to read until I
|
||||||
|
% finally figured out what you were driving at. Who makes this conceptual mistake?
|
||||||
|
% It may not be worthwhile... though I've seen other grad students make
|
||||||
|
% this mistake, and the TMPW2000 VTL paper contains this mistake.
|
||||||
|
|
||||||
|
The implementations of the constant and mutable versions of an
|
||||||
|
iterator typically differ only in their \code{reference} and
|
||||||
|
\code{pointer} types. Therefore it is desirable to merge the two
|
||||||
|
iterator classes into a single class template with the
|
||||||
|
\code{reference} and \code{pointer} types as template parameters.
|
||||||
|
|
||||||
|
Some care must be taken when merging the constant and mutable
|
||||||
|
iterators. One common mistake is that the programmer will confuse the
|
||||||
|
ideas of a \code{const} iterator object and a \emph{constant
|
||||||
|
iterator}. Such a misunderstanding can, for example, lead to an
|
||||||
|
iterator class template that has two versions of \code{operator*}, one
|
||||||
|
that is a \code{const} member function and one that is not.
|
||||||
|
|
||||||
|
{\footnotesize
|
||||||
|
\begin{verbatim}
|
||||||
|
// this is a mistake
|
||||||
|
reference operator*();
|
||||||
|
const_reference operator*() const;
|
||||||
|
\end{verbatim}
|
||||||
|
}
|
||||||
|
|
||||||
|
There should be only one \code{operator*} that returns the
|
||||||
|
\code{reference} type and the member function should be \code{const} since
|
||||||
|
dereferencing an iterator does not change the state of the iterator
|
||||||
|
object itself (unlike \code{operator++}).
|
||||||
|
|
||||||
|
{\footnotesize
|
||||||
|
\begin{verbatim}
|
||||||
|
// this is right
|
||||||
|
reference operator*() const;
|
||||||
|
\end{verbatim}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
\subsubsection{Input Iterators and \code{operator->}}
|
||||||
|
\label{sec:operator-arrow}
|
||||||
|
|
||||||
|
When creating an iterator adaptor that produces an
|
||||||
|
\stlconcept{InputIterator} some extra care must be taken in the
|
||||||
|
implementation of \code{operator->}. Remember that an input iterator
|
||||||
|
need not iterate over stored objects: it can manufacture new objects
|
||||||
|
when it is dereferenced as is the case for
|
||||||
|
\code{std::istream\_iterator}. If the iterator's \valuetype\ is
|
||||||
|
of class type, we need to support \code{operator->}. Since the result
|
||||||
|
of using \code{operator->} must produce a true pointer even when
|
||||||
|
dereferencing the iterator does not yield a true reference type, we
|
||||||
|
need a \code{const} lvalue to which a pointer can be formed. In
|
||||||
|
\S\ref{sec:operator-arrow} we show how this can be accomplished.
|
||||||
|
|
||||||
|
|
||||||
|
\subsubsection{The Return Type of \code{operator[]} for Adaptors}
|
||||||
|
\label{sec:operator-bracket}
|
||||||
|
|
||||||
|
The \Cpp\ 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 \Cpp\ 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 Implementation of \iteratoradaptor{}}
|
\section{The Implementation of \iteratoradaptor{}}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user