forked from boostorg/utility
some minor edits
[SVN r10331]
This commit is contained in:
@ -79,10 +79,10 @@ Adaptor Library. This generator simplifies the creation of iterators;
|
|||||||
it automates the error-prone and redundant parts of the implementation
|
it automates the error-prone and redundant parts of the implementation
|
||||||
and greatly simplifies the creation of iterator types that are
|
and greatly simplifies the creation of iterator types that are
|
||||||
variations on other iterators (adapted iterators). The Iterator
|
variations on other iterators (adapted iterators). The Iterator
|
||||||
Adaptor Library employs template meta-programming and is an example of
|
Adaptor Library is an example of policy-based design and employs
|
||||||
policy-based design. It uses an extremely flexible implementation
|
template meta-programming. It uses an extremely flexible
|
||||||
pattern which can be easily adapted to generate new representatives of
|
implementation pattern which can be easily adapted to generate new
|
||||||
other abstract Concept families.
|
representatives of other abstract Concept families.
|
||||||
|
|
||||||
\end{abstract}
|
\end{abstract}
|
||||||
|
|
||||||
@ -95,9 +95,9 @@ other abstract Concept families.
|
|||||||
|
|
||||||
Iterators play an important role in modern C++ programing. The
|
Iterators play an important role in modern C++ 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 and adapting old ones are
|
Library and creating new iterator types is a common task for C++
|
||||||
common tasks for C++ programmers. There are plenty of examples of
|
programmers. There are plenty of examples of iterators in the
|
||||||
iterators in the literature: the
|
literature: the
|
||||||
\code{line\_iterator}~\cite{austern99:_gener_progr_stl},
|
\code{line\_iterator}~\cite{austern99:_gener_progr_stl},
|
||||||
\code{Constant\_iterator}~\cite{koenig97:_rumin_cpp},
|
\code{Constant\_iterator}~\cite{koenig97:_rumin_cpp},
|
||||||
\code{std::istream\_iterator} and
|
\code{std::istream\_iterator} and
|
||||||
@ -229,7 +229,7 @@ type. It is desirable to allow the constant and mutable iterators to
|
|||||||
interoperate through comparison and
|
interoperate through comparison and
|
||||||
subtraction. For example, suppose
|
subtraction. For example, suppose
|
||||||
that you are implementing a container type \code{C}. Then you ought to
|
that you are implementing a container type \code{C}. Then you ought to
|
||||||
define the following four version of \code{operator==}, along with
|
define the following four versions of \code{operator==}, along with
|
||||||
corresponding versions of \code{operator!=}, and (for
|
corresponding versions of \code{operator!=}, and (for
|
||||||
\stlconcept{RandomAccessIterator}), operators \code{<}, \code{>},
|
\stlconcept{RandomAccessIterator}), operators \code{<}, \code{>},
|
||||||
\code{<=}, \code{>=}, and \code{-}.
|
\code{<=}, \code{>=}, and \code{-}.
|
||||||
@ -344,7 +344,7 @@ the primary communication mechanism between the iterator implementer
|
|||||||
and the \code{iterator\_\-adaptor}; it specifies how the new iterator
|
and the \code{iterator\_\-adaptor}; 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
|
||||||
implementation.
|
implementation.
|
||||||
|
|
||||||
\subsection{Iterator Policies Class}
|
\subsection{Iterator Policies Class}
|
||||||
@ -523,7 +523,7 @@ following constructor.
|
|||||||
}
|
}
|
||||||
|
|
||||||
It would be cumbersome for the user to call this constructor since
|
It would be cumbersome for the user to call this constructor since
|
||||||
they would have to separately construct a policies class object and
|
they would have to separately construct a policies object and
|
||||||
then the iterator object. We therefore recommend that iterator
|
then the iterator object. We therefore recommend that iterator
|
||||||
implementers create an \emph{object generator} function for their
|
implementers create an \emph{object generator} function for their
|
||||||
iterator. The following is the generator function for the transform
|
iterator. The following is the generator function for the transform
|
||||||
@ -620,7 +620,7 @@ namespace boost {
|
|||||||
// the policies are ``second''.
|
// the policies are ``second''.
|
||||||
Policies& policies() { return m_iter_p.second(); }
|
Policies& policies() { return m_iter_p.second(); }
|
||||||
Base& iter() { return m_iter_p.first(); }
|
Base& iter() { return m_iter_p.first(); }
|
||||||
// and the same for const references...
|
// and similarly for const...
|
||||||
};
|
};
|
||||||
// Core binary operators.
|
// Core binary operators.
|
||||||
// Redundant binary operators.
|
// Redundant binary operators.
|
||||||
@ -658,13 +658,11 @@ default was used for \code{value\_type} then the \code{reference} and
|
|||||||
\subsubsection{Named Template Parameters}
|
\subsubsection{Named Template Parameters}
|
||||||
\label{sec:named-template-parameters}
|
\label{sec:named-template-parameters}
|
||||||
|
|
||||||
The \code{iterator\_adaptor} class has five template parameters that
|
Since each of the parameters for the associated types has a default
|
||||||
specify the associated types of the iterator. Each of the parameters
|
user may specify zero or more of them. One difficulty with {C++}
|
||||||
has defaults as described above, so the user may specify zero or more
|
templates is that if a default is used for a parameter then all the
|
||||||
parameters. One difficulty with {C++} templates is that if a default
|
following parameters must also be default. When there are a large
|
||||||
is used for a parameter then all the following parameters must also be
|
number of parameters this becomes inconvenient.
|
||||||
default. When there are a large number of parameters this becomes
|
|
||||||
inconvenient.
|
|
||||||
|
|
||||||
A solution to this problem is the idea of named parameters. Instead
|
A solution to this problem is the idea of named parameters. Instead
|
||||||
of matching arguments to parameters based on order, the assignment of
|
of matching arguments to parameters based on order, the assignment of
|
||||||
@ -682,13 +680,13 @@ example:
|
|||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
}
|
}
|
||||||
|
|
||||||
Instead of passing the argument for the \code{Value} type directly to
|
Instead of passing the argument \code{Value} directly to
|
||||||
\code{iterator\_\-adaptor} the user passes
|
\code{iterator\_\-adaptor} the user passes
|
||||||
\code{value\_type\_is<Value>}. The \code{iterator\_\-adaptor} now has
|
\code{value\_type\_is<Value>}. The \code{iterator\_\-adaptor} 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
|
\code{iterator\_\-adaptor} must deduce which argument is for which
|
||||||
parameter based on the \code{tag} type 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
|
||||||
lisp-style list, using \code{std::pair} for \code{cons}. Each
|
lisp-style list, using \code{std::pair} for \code{cons}. Each
|
||||||
@ -806,31 +804,37 @@ in the following two sections.
|
|||||||
\subsubsection{Implementing \code{operator->} for Input Iterators}
|
\subsubsection{Implementing \code{operator->} for Input Iterators}
|
||||||
\label{sec:operator-arrow}
|
\label{sec:operator-arrow}
|
||||||
|
|
||||||
Fortunately, the standard gives us a way: section 13.3.1.2 paragraph 8
|
As introduced in \S\ref{sec:operator-arrow}, it is difficult to
|
||||||
describes a seemingly quirky rule that the \code{->} operator will be
|
implement \code{operator->} for input iterators because there may not
|
||||||
applied to the \emph{result} of any call to \code{operator->}. This is
|
be an lvalue from which to form a pointer.
|
||||||
a convenient way to describe the semantics of ordinary
|
|
||||||
\code{operator->}, which returns a pointer: it just uses the pointer
|
Fortunately, the standard makes a workaround possible: section
|
||||||
to perform the usual member dereferencing. It also turns out to be
|
13.3.1.2 paragraph 8 describes a seemingly quirky rule that the
|
||||||
what we need to make a conforming \stlconcept{InputIterator}. By
|
\code{->} operator will be applied to the \emph{result} of any call to
|
||||||
making the return type of \code{operator->} a proxy containing an
|
\code{operator->}. This is a convenient way to describe the semantics
|
||||||
instance of the iterator's \code{value\_type}, we can eventually form
|
of ordinary \code{operator->}, which returns a pointer: it just uses
|
||||||
a \code{const} pointer to the returned temporary:
|
the pointer to perform the usual member dereferencing. It also turns
|
||||||
|
out to be what we need to make a conforming
|
||||||
|
\stlconcept{InputIterator}. By making the return type of
|
||||||
|
\code{operator->} a proxy containing an instance of the iterator's
|
||||||
|
\code{value\_type}, we can eventually form a \code{const} pointer to
|
||||||
|
the returned temporary:
|
||||||
|
|
||||||
{\footnotesize
|
{\footnotesize
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
template <class T>
|
template <class T>
|
||||||
struct operator_arrow_proxy
|
struct operator_arrow_proxy
|
||||||
{
|
{
|
||||||
operator_arrow_proxy(const T& x) : m_value(x) {}
|
operator_arrow_proxy(const T& x) : m_value(x) {}
|
||||||
const T* operator->() const { return &m_value; }
|
const T* operator->() const { return &m_value; }
|
||||||
T m_value;
|
T m_value;
|
||||||
};
|
};
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
}
|
}
|
||||||
|
|
||||||
The iterator adaptor library uses a small meta-program to select the
|
\noindent The iterator adaptor library uses a small meta-program to
|
||||||
appropriate type for the result of an iterator's \code{operator->}:
|
select the appropriate type for the result of an iterator's
|
||||||
|
\code{operator->}:
|
||||||
|
|
||||||
{\footnotesize
|
{\footnotesize
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
@ -843,7 +847,7 @@ appropriate type for the result of an iterator's \code{operator->}:
|
|||||||
&& !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}
|
||||||
}
|
}
|
||||||
@ -856,10 +860,11 @@ iterator categories derived from the standard ones.
|
|||||||
|
|
||||||
|
|
||||||
\subsubsection{Implementation of \code{operator[]}}
|
\subsubsection{Implementation of \code{operator[]}}
|
||||||
|
\label{sec:op-bracket-impl}
|
||||||
|
|
||||||
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:iterator-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
|
\code{iterator\_adaptor} 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.
|
||||||
@ -937,14 +942,14 @@ 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
|
iterators, implementing {C++} Standard conforming iterators requires a
|
||||||
is non-trivial amount of code: some of which is challenging to get
|
non-trivial amount of code: some of which is challenging to get right
|
||||||
right, and a lot of which is tedious to write. The
|
and a lot of which is tedious. The \code{iterator\_adaptor} class that
|
||||||
\code{iterator\_adaptor} class that we present in this paper solves
|
we present in this paper solves this problem by providing a mechanism
|
||||||
this problem by providing a mechanism by which the user provides a
|
by which the user provides a minimal specification (by way of the
|
||||||
minimal specification (by way of the policies class) for the iterator,
|
policies class) for the iterator, and then the
|
||||||
and then the \code{iterator\_\-adaptor} takes care of most of the
|
\code{iterator\_\-adaptor} takes care of most of the implementation
|
||||||
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
|
||||||
implementation of a concept (iterator) and then delegate the core
|
implementation of a concept (iterator) and then delegate the core
|
||||||
|
Reference in New Issue
Block a user