no message

[SVN r10336]
This commit is contained in:
Dave Abrahams
2001-06-15 02:23:19 +00:00
parent 2f9bd13902
commit 3e5b447aa3

View File

@ -136,7 +136,7 @@ despite the fact that most iterators are conceptually simple.
Perhaps the most obvious reason that implementing an iterator can Perhaps the most obvious reason that implementing an iterator can
be tedious is that there are lots of redundant operators. That is, be tedious is that there are lots of redundant operators. That is,
there are many operators that can be trivially defined in terms of there are many operators that can be trivially defined in terms of
other operators. For example, the post-fix \code{operator++(int)} is often best other operators. For example, the postfix \code{operator++(int)} is often best
implemented in terms of prefix \code{operator++()} as shown below. implemented in terms of prefix \code{operator++()} as shown below.
{\footnotesize {\footnotesize
@ -349,13 +349,17 @@ implementation.
\subsection{Iterator Policies Class} \subsection{Iterator Policies Class}
In the following we show an example of implementing the policies class The following example shows how to implement the policies class for a transform
for a transform iterator adaptor: an iterator that applies some iterator adaptor: an iterator that applies some function to the value returned
function to the value returned by dereferencing the base iterator. by dereferencing the base iterator. The
The \code{transform\_\-iterator\_\-policies} class is templated on the \code{transform\_\-iterator\_\-policies} class is templated on the function
function object type, and a function object is stored as a data member object type, and a function object is stored as a data member of the policies
of the policies class. In general, any extra state needed by the class. When adapting an underlying iterator, it is easiest to store any extra state
iterator should be stored in the policies class. The policies class needed by the resulting adapted iterator in the policies class rather than
incorporating it into the \code{Base} type because \code{iterator\_\-adaptor}
provides so many useful defaults when the \code{Base} type is an iterator.
The policies class
inherits from \code{default\_\-iterator\_\-policies}, which delegates inherits from \code{default\_\-iterator\_\-policies}, which delegates
all other operations to the base iterator. The main event of the all other operations to the base iterator. The main event of the
\code{transform\_\-iterator\_\-policies} class is the \code{transform\_\-iterator\_\-policies} class is the
@ -373,9 +377,11 @@ with any base iterator type.
transform_iterator_policies() { } transform_iterator_policies() { }
transform_iterator_policies(const AdaptableUnaryFunction& f) transform_iterator_policies(const AdaptableUnaryFunction& f)
: m_f(f) { } : m_f(f) { }
template <class Reference, class BaseIterator> template <class Reference, class BaseIterator>
Reference dereference(type<Reference>, const BaseIterator& i) const Reference dereference(type<Reference>, const BaseIterator& i) const
{ return m_f(*i); } // apply the function and return the result { return m_f(*i); } // apply the function and return the result
AdaptableUnaryFunction m_f; AdaptableUnaryFunction m_f;
}; };
\end{verbatim} \end{verbatim}
@ -387,7 +393,7 @@ perhaps not the most elegant, but it was the most portable solution.
A policies class is required to have a default constructor because the A policies class is required to have a default constructor because the
\code{iterator\_\-adaptor} has an instance of the policies class as a \code{iterator\_\-adaptor} has an instance of the policies class as a
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.
@ -404,15 +410,15 @@ iterator type is constructed using \code{iterator\_\-adaptor}.
\subsection{Default Iterator Policies Class} \subsection{Default Iterator Policies Class}
The \code{default\_\-iterator\_\-policies} class is the mechanism that The \code{default\_\-iterator\_\-policies} class is the mechanism that
provides automatic delegation to the base iterator, freeing the automatically delegates operator implementations to the base iterator,
iterator implementer from the tedious task of writing delegating freeing the iterator implementer from the tedious task of writing
functions. As above, an iterator policies class inherits from this delegating functions. As above, an iterator policies class inherits
class and overrides any functions that should not be delegated. The from this class and overrides any functions that should not be
\code{default\_\-iterator\_\-policies} class also serves as an example delegated. The \code{default\_\-iterator\_\-policies} class also
of the iterator policies interface. There are seven member functions serves as an example of the iterator policies interface. There are
that correspond to the core iterator operations and an seven member functions corresponding to the core iterator operations
\code{initialize()} function to provide a hook for customization of and an \code{initialize()} function which provides a hook for
iterator construction. customized iterator construction.
{\footnotesize {\footnotesize
\begin{verbatim} \begin{verbatim}
@ -532,14 +538,16 @@ iterator adaptor.
{\footnotesize {\footnotesize
\begin{verbatim} \begin{verbatim}
template <class AdaptableUnaryFunction, class Iterator> template <class AdaptableUnaryFunction, class Iterator>
typename transform_iterator_generator<AdaptableUnaryFunction, typename transform_iterator_generator<
Iterator>::type AdaptableUnaryFunction, Iterator>::type
make_transform_iterator(Iterator base, make_transform_iterator(Iterator base,
const AdaptableUnaryFunction& f = AdaptableUnaryFunction()) const AdaptableUnaryFunction& f = AdaptableUnaryFunction())
{ {
typedef typename transform_iterator_generator<AdaptableUnaryFunction, typedef typename transform_iterator_generator<AdaptableUnaryFunction,
Iterator>::type result_t; Iterator>::type result_t;
transform_iterator_policies<AdaptableUnaryFunction> policies(f); transform_iterator_policies<AdaptableUnaryFunction> policies(f);
return result_t(base, policies); return result_t(base, policies);
} }
\end{verbatim} \end{verbatim}
@ -609,7 +617,7 @@ namespace boost {
class Param5 = default_argument> class Param5 = default_argument>
struct iterator_adaptor { struct iterator_adaptor {
// Deduce iterator associated types (value_type, etc.) from the // Deduce iterator associated types (value_type, etc.) from the
// named template parameters, and resolve any defaults. // named template parameters, and resolve any defaults.
public: public:
// Core operators, delegate to policies class. // Core operators, delegate to policies class.
// Redundant operators, implemented in terms of the core operators. // Redundant operators, implemented in terms of the core operators.
@ -847,7 +855,10 @@ select the appropriate type for the result of an iterator's
&& !is_convertible<Category*,std::forward_iterator_tag*>::value; && !is_convertible<Category*,std::forward_iterator_tag*>::value;
typedef typename type_if<is_input_iter, typedef typename type_if<is_input_iter,
operator_arrow_proxy<Value>, /*else*/ Pointer>::type type; operator_arrow_proxy<Value>,
// else
Pointer
>::type type;
}; };
\end{verbatim} \end{verbatim}
} }
@ -869,7 +880,7 @@ the issue surrounding what the return type should be. As mentioned in
\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.
Suppose the adapted iterator is reading in elements from a file and Suppose the base iterator is reading in elements from a file and
caching each element as a data member of the iterator. caching each element as a data member of the iterator.
{\footnotesize {\footnotesize
@ -893,7 +904,7 @@ the data member. Now consider what happens inside the
{\footnotesize {\footnotesize
\begin{verbatim} \begin{verbatim}
template <class Iterator> class iter_adaptor { template <class Iterator> class iterator_adaptor {
Iterator iter; Iterator iter;
public: public:
reference operator[](difference_type n) const { reference operator[](difference_type n) const {
@ -905,12 +916,11 @@ public:
} }
\noindent The iterator addition creates a temporary iterator and the \noindent The iterator addition creates a temporary iterator and the
dereference returns a reference to a data member of this dereference returns a reference to a data member of this temporary,
temporary. The result is a dangling reference being returned from which is destroyed before \code{operator[]} returns. The result is a
\code{operator[]}. dangling reference.
Boost's \code{iterator\_adaptor} takes the safe route and returns the
The \code{iterator\_adaptor} 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'',
@ -927,15 +937,23 @@ in a generic algorithm, you can not use \code{operator[]} for
assignment (on the left hand side) but instead must write \code{*(i + assignment (on the left hand side) but instead must write \code{*(i +
n) = x}. n) = x}.
Alternatively, it would be nice to return by-reference for some It would be nice to return by-reference for iterators that can support
iterators and by-value for others. However, the current it, and by-value for the rest. However, the current
\code{iterator\_\-traits} does not provide enough information make the \code{iterator\_\-traits} does not provide enough information make the
choice. In addition, the lack of consistency between \code{operator[]} choice.
and \code{operator*} will be surprising to people. Preferably an
iterator would either return by-value for both \code{operator*} and % Jeremy: I didn't agree with this part, so commented it out
\code{operator[]} or return by-reference for both. The proposal % temporarily. I think an iterator which can return by-reference for
in~\cite{siek01:_improved_iter_cat} would solves these problems, but % operator* should be allowed to do so, regardless of what it can do
of course that will take some time to gain acceptance. % for operator[]. Let's discuss.
% In addition, the lack of consistency between \code{operator[]}
% and \code{operator*} will be surprising to people. Preferably an
% iterator would either return by-value for both \code{operator*} and
% \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}
@ -943,9 +961,9 @@ of course that will take some time to gain acceptance.
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 C++ programming. Despite the conceptual simplicity of most
iterators, implementing {C++} Standard conforming iterators requires a iterators, implementing {C++} 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 \code{iterator\_adaptor} class that
we present in this paper solves this 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 \code{iterator\_\-adaptor} takes care of most of the implementation
@ -958,7 +976,6 @@ applied in situations where there is large family of components that
share the same interface. For example, we plan on applying this design share the same interface. For example, we plan on applying this design
approach to containers and algebraic types. approach to containers and algebraic types.
\bibliographystyle{abbrv} \bibliographystyle{abbrv}
\bibliography{refs,tmpw00} \bibliography{refs,tmpw00}