forked from boostorg/utility
no message
[SVN r10336]
This commit is contained in:
@ -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}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user