forked from boostorg/iterator
This commit was manufactured by cvs2svn to create branch 'RC_1_31_0'.
[SVN r21755]
This commit is contained in:
53
doc/facade_iterator_category.rst
Executable file
53
doc/facade_iterator_category.rst
Executable file
@ -0,0 +1,53 @@
|
|||||||
|
.. |iterator-category| replace:: *iterator-category*
|
||||||
|
.. _iterator-category:
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
*iterator-category*\ (C,R,V) :=
|
||||||
|
if (C is convertible to std::input_iterator_tag
|
||||||
|
|| C is convertible to std::output_iterator_tag
|
||||||
|
)
|
||||||
|
return C
|
||||||
|
|
||||||
|
else if (C is not convertible to incrementable_traversal_tag)
|
||||||
|
*the program is ill-formed*
|
||||||
|
|
||||||
|
else return a type X satisfying the following two constraints:
|
||||||
|
|
||||||
|
1. X is convertible to X1, and not to any more-derived
|
||||||
|
type, where X1 is defined by:
|
||||||
|
|
||||||
|
if (R is a reference type
|
||||||
|
&& C is convertible to forward_traversal_tag)
|
||||||
|
{
|
||||||
|
if (C is convertible to random_access_traversal_tag)
|
||||||
|
X1 = random_access_iterator_tag
|
||||||
|
else if (C is convertible to bidirectional_traversal_tag)
|
||||||
|
X1 = bidirectional_iterator_tag
|
||||||
|
else
|
||||||
|
X1 = forward_iterator_tag
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (C is convertible to single_pass_traversal_tag
|
||||||
|
&& R is convertible to V)
|
||||||
|
X1 = input_iterator_tag
|
||||||
|
else
|
||||||
|
X1 = C
|
||||||
|
}
|
||||||
|
|
||||||
|
2. |category-to-traversal|_\ (X) is convertible to the most
|
||||||
|
derived traversal tag type to which X is also
|
||||||
|
convertible, and not to any more-derived traversal tag
|
||||||
|
type.
|
||||||
|
|
||||||
|
.. |category-to-traversal| replace:: *category-to-traversal*
|
||||||
|
.. _`category-to-traversal`: new-iter-concepts.html#category-to-traversal
|
||||||
|
|
||||||
|
[Note: the intention is to allow ``iterator_category`` to be one of
|
||||||
|
the five original category tags when convertibility to one of the
|
||||||
|
traversal tags would add no information]
|
||||||
|
|
||||||
|
.. Copyright David Abrahams 2004. Use, modification and distribution is
|
||||||
|
.. subject to the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
29
doc/indirect_reference_ref.rst
Executable file
29
doc/indirect_reference_ref.rst
Executable file
@ -0,0 +1,29 @@
|
|||||||
|
.. Copyright David Abrahams 2004. Use, modification and distribution is
|
||||||
|
.. subject to the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
template <class Dereferenceable>
|
||||||
|
struct indirect_reference
|
||||||
|
{
|
||||||
|
typedef /* see below */ type;
|
||||||
|
};
|
||||||
|
|
||||||
|
:Requires: For an object ``x`` of type ``Dereferenceable``, ``*x``
|
||||||
|
is well-formed. If ``++x`` is ill-formed it shall neither be
|
||||||
|
ambiguous nor shall it violate access control, and
|
||||||
|
``pointee<Dereferenceable>::type&`` shall be well-formed.
|
||||||
|
Otherwise ``iterator_traits<Dereferenceable>::reference`` shall
|
||||||
|
be well formed. [Note: These requirements need not apply to
|
||||||
|
explicit or partial specializations of ``indirect_reference``]
|
||||||
|
|
||||||
|
``type`` is determined according to the following algorithm, where
|
||||||
|
``x`` is an object of type ``Dereferenceable``::
|
||||||
|
|
||||||
|
if ( ++x is ill-formed )
|
||||||
|
return ``pointee<Dereferenceable>::type&``
|
||||||
|
else
|
||||||
|
std::iterator_traits<Dereferenceable>::reference
|
||||||
|
|
||||||
|
|
131
doc/iterator_adaptor_tutorial.rst
Executable file
131
doc/iterator_adaptor_tutorial.rst
Executable file
@ -0,0 +1,131 @@
|
|||||||
|
.. Copyright David Abrahams 2004. Use, modification and distribution is
|
||||||
|
.. subject to the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
In this section we'll further refine the ``node_iter`` class
|
||||||
|
template we developed in the |fac_tut|_. If you haven't already
|
||||||
|
read that material, you should go back now and check it out because
|
||||||
|
we're going to pick up right where it left off.
|
||||||
|
|
||||||
|
.. |fac_tut| replace:: ``iterator_facade`` tutorial
|
||||||
|
.. _fac_tut: iterator_facade.html#tutorial-example
|
||||||
|
|
||||||
|
.. sidebar:: ``node_base*`` really *is* an iterator
|
||||||
|
|
||||||
|
It's not really a very interesting iterator, since ``node_base``
|
||||||
|
is an abstract class: a pointer to a ``node_base`` just points
|
||||||
|
at some base subobject of an instance of some other class, and
|
||||||
|
incrementing a ``node_base*`` moves it past this base subobject
|
||||||
|
to who-knows-where? The most we can do with that incremented
|
||||||
|
position is to compare another ``node_base*`` to it. In other
|
||||||
|
words, the original iterator traverses a one-element array.
|
||||||
|
|
||||||
|
You probably didn't think of it this way, but the ``node_base*``
|
||||||
|
object which underlies ``node_iterator`` is itself an iterator,
|
||||||
|
just like all other pointers. If we examine that pointer closely
|
||||||
|
from an iterator perspective, we can see that it has much in common
|
||||||
|
with the ``node_iterator`` we're building. First, they share most
|
||||||
|
of the same associated types (``value_type``, ``reference``,
|
||||||
|
``pointer``, and ``difference_type``). Second, even some of the
|
||||||
|
core functionality is the same: ``operator*`` and ``operator==`` on
|
||||||
|
the ``node_iterator`` return the result of invoking the same
|
||||||
|
operations on the underlying pointer, via the ``node_iterator``\ 's
|
||||||
|
|dereference_and_equal|_). However, the ``operator++`` for
|
||||||
|
``node_iterator`` behaves differently than for ``node_base*``
|
||||||
|
since it follows the ``m_next`` pointer.
|
||||||
|
|
||||||
|
.. |dereference_and_equal| replace:: ``dereference`` and ``equal`` member functions
|
||||||
|
.. _dereference_and_equal: iterator_facade.html#implementing-the-core-operations
|
||||||
|
|
||||||
|
It turns out that the pattern of building an iterator on another
|
||||||
|
iterator-like type (the ``Base`` [#base]_ type) while modifying
|
||||||
|
just a few aspects of the underlying type's behavior is an
|
||||||
|
extremely common one, and it's the pattern addressed by
|
||||||
|
``iterator_adaptor``. Using ``iterator_adaptor`` is very much like
|
||||||
|
using ``iterator_facade``, but because iterator_adaptor tries to
|
||||||
|
mimic as much of the ``Base`` type's behavior as possible, we
|
||||||
|
neither have to supply a ``Value`` argument, nor implement any core
|
||||||
|
behaviors other than ``increment``. The implementation of
|
||||||
|
``node_iter`` is thus reduced to::
|
||||||
|
|
||||||
|
template <class Value>
|
||||||
|
class node_iter
|
||||||
|
: public boost::iterator_adaptor<
|
||||||
|
node_iter<Value> // Derived
|
||||||
|
, Value* // Base
|
||||||
|
, boost::use_default // Value
|
||||||
|
, boost::forward_traversal_tag // CategoryOrTraversal
|
||||||
|
>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
struct enabler {}; // a private type avoids misuse
|
||||||
|
|
||||||
|
typedef boost::iterator_adaptor<
|
||||||
|
node_iter<Value>, Value*, boost::use_default, boost::forward_traversal_tag
|
||||||
|
> super_t;
|
||||||
|
|
||||||
|
public:
|
||||||
|
node_iter()
|
||||||
|
: super_t(0) {}
|
||||||
|
|
||||||
|
explicit node_iter(Value* p)
|
||||||
|
: super_t(p) {}
|
||||||
|
|
||||||
|
template <class OtherValue>
|
||||||
|
node_iter(
|
||||||
|
node_iter<OtherValue> const& other
|
||||||
|
, typename boost::enable_if<
|
||||||
|
boost::is_convertible<OtherValue*,Value*>
|
||||||
|
, enabler
|
||||||
|
>::type = enabler()
|
||||||
|
)
|
||||||
|
: super_t(other.base()) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class boost::iterator_core_access;
|
||||||
|
void increment() { this->base_reference() = this->base()->next(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
You can see an example program which exercises this version of the
|
||||||
|
node iterators `here`__.
|
||||||
|
|
||||||
|
__ ../example/node_iterator3.cpp
|
||||||
|
|
||||||
|
In the case of ``node_iter``, it's not very compelling to pass
|
||||||
|
``boost::use_default`` as ``iterator_adaptor``\ 's ``Value``
|
||||||
|
argument; we could have just passed ``node_iter``\ 's ``Value``
|
||||||
|
along to ``iterator_adaptor``, and that'd even be shorter! Most
|
||||||
|
iterator class templates built with ``iterator_adaptor`` are
|
||||||
|
parameterized on another iterator type, rather than on its
|
||||||
|
``value_type``. For example, ``boost::reverse_iterator`` takes an
|
||||||
|
iterator type argument and reverses its direction of traversal,
|
||||||
|
since the original iterator and the reversed one have all the same
|
||||||
|
associated types, ``iterator_adaptor``\ 's delegation of default
|
||||||
|
types to its ``Base`` saves the implementor of
|
||||||
|
``boost::reverse_iterator`` from writing
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
std::iterator_traits<Iterator>::*some-associated-type*
|
||||||
|
|
||||||
|
at least four times.
|
||||||
|
|
||||||
|
We urge you to review the documentation and implementations of
|
||||||
|
|reverse_iterator|_ and the other Boost `specialized iterator
|
||||||
|
adaptors`__ to get an idea of the sorts of things you can do with
|
||||||
|
``iterator_adaptor``. In particular, have a look at
|
||||||
|
|transform_iterator|_, which is perhaps the most straightforward
|
||||||
|
adaptor, and also |counting_iterator|_, which demonstrates that
|
||||||
|
``iterator_adaptor``\ 's ``Base`` type needn't be an iterator.
|
||||||
|
|
||||||
|
.. |reverse_iterator| replace:: ``reverse_iterator``
|
||||||
|
.. _reverse_iterator: reverse_iterator.html
|
||||||
|
|
||||||
|
.. |counting_iterator| replace:: ``counting_iterator``
|
||||||
|
.. _counting_iterator: counting_iterator.html
|
||||||
|
|
||||||
|
.. |transform_iterator| replace:: ``transform_iterator``
|
||||||
|
.. _transform_iterator: transform_iterator.html
|
||||||
|
|
||||||
|
__ index.html#specialized-adaptors
|
||||||
|
|
519
doc/iterator_facade_tutorial.rst
Executable file
519
doc/iterator_facade_tutorial.rst
Executable file
@ -0,0 +1,519 @@
|
|||||||
|
.. Copyright David Abrahams 2004. Use, modification and distribution is
|
||||||
|
.. subject to the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
In this section we'll walk through the implementation of a few
|
||||||
|
iterators using ``iterator_facade``, based around the simple
|
||||||
|
example of a linked list of polymorphic objects. This example was
|
||||||
|
inspired by a `posting`__ by Keith Macdonald on the `Boost-Users`_
|
||||||
|
mailing list.
|
||||||
|
|
||||||
|
.. _`Boost-Users`: ../../../more/mailing_lists.htm#users
|
||||||
|
|
||||||
|
__ http://thread.gmane.org/gmane.comp.lib.boost.user/5100
|
||||||
|
|
||||||
|
The Problem
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Say we've written a polymorphic linked list node base class::
|
||||||
|
|
||||||
|
# include <iostream>
|
||||||
|
|
||||||
|
struct node_base
|
||||||
|
{
|
||||||
|
node_base() : m_next(0) {}
|
||||||
|
|
||||||
|
// Each node manages all of its tail nodes
|
||||||
|
virtual ~node_base() { delete m_next; }
|
||||||
|
|
||||||
|
// Access the rest of the list
|
||||||
|
node_base* next() const { return m_next; }
|
||||||
|
|
||||||
|
// print to the stream
|
||||||
|
virtual void print(std::ostream& s) const = 0;
|
||||||
|
|
||||||
|
// double the value
|
||||||
|
virtual void double_me() = 0;
|
||||||
|
|
||||||
|
void append(node_base* p)
|
||||||
|
{
|
||||||
|
if (m_next)
|
||||||
|
m_next->append(p);
|
||||||
|
else
|
||||||
|
m_next = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
node_base* m_next;
|
||||||
|
};
|
||||||
|
|
||||||
|
Lists can hold objects of different types by linking together
|
||||||
|
specializations of the following template::
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct node : node_base
|
||||||
|
{
|
||||||
|
node(T x)
|
||||||
|
: m_value(x)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void print(std::ostream& s) const { s << this->m_value; }
|
||||||
|
void double_me() { m_value += m_value; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
T m_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
And we can print any node using the following streaming operator::
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& s, node_base const& n)
|
||||||
|
{
|
||||||
|
n.print(s);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
Our first challenge is to build an appropriate iterator over these
|
||||||
|
lists.
|
||||||
|
|
||||||
|
A Basic Iterator Using ``iterator_facade``
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
We will construct a ``node_iterator`` class using inheritance from
|
||||||
|
``iterator_facade`` to implement most of the iterator's operations.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
# include "node.hpp"
|
||||||
|
# include <boost/iterator/iterator_facade.hpp>
|
||||||
|
|
||||||
|
class node_iterator
|
||||||
|
: public boost::iterator_facade<...>
|
||||||
|
{
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Template Arguments for ``iterator_facade``
|
||||||
|
..........................................
|
||||||
|
|
||||||
|
``iterator_facade`` has several template parameters, so we must decide
|
||||||
|
what types to use for the arguments. The parameters are ``Derived``,
|
||||||
|
``Value``, ``CategoryOrTraversal``, ``Reference``, and ``Difference``.
|
||||||
|
|
||||||
|
|
||||||
|
``Derived``
|
||||||
|
'''''''''''
|
||||||
|
|
||||||
|
Because ``iterator_facade`` is meant to be used with the CRTP
|
||||||
|
[Cop95]_ the first parameter is the iterator class name itself,
|
||||||
|
``node_iterator``.
|
||||||
|
|
||||||
|
``Value``
|
||||||
|
'''''''''
|
||||||
|
|
||||||
|
The ``Value`` parameter determines the ``node_iterator``\ 's
|
||||||
|
``value_type``. In this case, we are iterating over ``node_base``
|
||||||
|
objects, so ``Value`` will be ``node_base``.
|
||||||
|
|
||||||
|
|
||||||
|
``CategoryOrTraversal``
|
||||||
|
'''''''''''''''''''''''
|
||||||
|
|
||||||
|
Now we have to determine which `iterator traversal concept`_ our
|
||||||
|
``node_iterator`` is going to model. Singly-linked lists only have
|
||||||
|
forward links, so our iterator can't can't be a `bidirectional
|
||||||
|
traversal iterator`_. Our iterator should be able to make multiple
|
||||||
|
passes over the same linked list (unlike, say, an
|
||||||
|
``istream_iterator`` which consumes the stream it traverses), so it
|
||||||
|
must be a `forward traversal iterator`_. Therefore, we'll pass
|
||||||
|
``boost::forward_traversal_tag`` in this position [#category]_.
|
||||||
|
|
||||||
|
.. [#category] ``iterator_facade`` also supports old-style category
|
||||||
|
tags, so we could have passed ``std::forward_iterator_tag`` here;
|
||||||
|
either way, the resulting iterator's ``iterator_category`` will
|
||||||
|
end up being ``std::forward_iterator_tag``.
|
||||||
|
|
||||||
|
``Reference``
|
||||||
|
'''''''''''''
|
||||||
|
|
||||||
|
The ``Reference`` argument becomes the type returned by
|
||||||
|
``node_iterator``\ 's dereference operation, and will also be the
|
||||||
|
same as ``std::iterator_traits<node_iterator>::reference``. The
|
||||||
|
library's default for this parameter is ``Value&``; since
|
||||||
|
``node_base&`` is a good choice for the iterator's ``reference``
|
||||||
|
type, we can omit this argument, or pass ``use_default``.
|
||||||
|
|
||||||
|
``Difference``
|
||||||
|
''''''''''''''
|
||||||
|
|
||||||
|
The ``Difference`` argument determines how the distance between
|
||||||
|
two ``node_iterator``\ s will be measured and will also be the
|
||||||
|
same as ``std::iterator_traits<node_iterator>::difference_type``.
|
||||||
|
The library's default for ``Difference`` is ``std::ptrdiff_t``, an
|
||||||
|
appropriate type for measuring the distance between any two
|
||||||
|
addresses in memory, and one that works for almost any iterator,
|
||||||
|
so we can omit this argument, too.
|
||||||
|
|
||||||
|
The declaration of ``node_iterator`` will therefore look something
|
||||||
|
like::
|
||||||
|
|
||||||
|
# include "node.hpp"
|
||||||
|
# include <boost/iterator/iterator_facade.hpp>
|
||||||
|
|
||||||
|
class node_iterator
|
||||||
|
: public boost::iterator_facade<
|
||||||
|
node_iterator
|
||||||
|
, node_base
|
||||||
|
, boost::forward_traversal_tag
|
||||||
|
>
|
||||||
|
{
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
Constructors and Data Members
|
||||||
|
.............................
|
||||||
|
|
||||||
|
Next we need to decide how to represent the iterator's position.
|
||||||
|
This representation will take the form of data members, so we'll
|
||||||
|
also need to write constructors to initialize them. The
|
||||||
|
``node_iterator``\ 's position is quite naturally represented using
|
||||||
|
a pointer to a ``node_base``. We'll need a constructor to build an
|
||||||
|
iterator from a ``node_base*``, and a default constructor to
|
||||||
|
satisfy the `forward traversal iterator`_ requirements [#default]_.
|
||||||
|
Our ``node_iterator`` then becomes::
|
||||||
|
|
||||||
|
# include "node.hpp"
|
||||||
|
# include <boost/iterator/iterator_facade.hpp>
|
||||||
|
|
||||||
|
class node_iterator
|
||||||
|
: public boost::iterator_facade<
|
||||||
|
node_iterator
|
||||||
|
, node_base
|
||||||
|
, boost::forward_traversal_tag
|
||||||
|
>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
node_iterator()
|
||||||
|
: m_node(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit node_iterator(node_base* p)
|
||||||
|
: m_node(p)
|
||||||
|
{}
|
||||||
|
|
||||||
|
private:
|
||||||
|
...
|
||||||
|
node_base* m_node;
|
||||||
|
};
|
||||||
|
|
||||||
|
.. [#default] Technically, the C++ standard places almost no
|
||||||
|
requirements on a default-constructed iterator, so if we were
|
||||||
|
really concerned with efficiency, we could've written the
|
||||||
|
default constructor to leave ``m_node`` uninitialized.
|
||||||
|
|
||||||
|
Implementing the Core Operations
|
||||||
|
................................
|
||||||
|
|
||||||
|
The last step is to implement the `core operations`_ required by
|
||||||
|
the concepts we want our iterator to model. Referring to the
|
||||||
|
table__, we can see that the first three rows are applicable
|
||||||
|
because ``node_iterator`` needs to satisfy the requirements for
|
||||||
|
`readable iterator`_, `single pass iterator`_, and `incrementable
|
||||||
|
iterator`_.
|
||||||
|
|
||||||
|
__ `core operations`_
|
||||||
|
|
||||||
|
We therefore need to supply ``dereference``,
|
||||||
|
``equal``, and ``increment`` members. We don't want these members
|
||||||
|
to become part of ``node_iterator``\ 's public interface, so we can
|
||||||
|
make them private and grant friendship to
|
||||||
|
``boost::iterator_core_access``, a "back-door" that
|
||||||
|
``iterator_facade`` uses to get access to the core operations::
|
||||||
|
|
||||||
|
# include "node.hpp"
|
||||||
|
# include <boost/iterator/iterator_facade.hpp>
|
||||||
|
|
||||||
|
class node_iterator
|
||||||
|
: public boost::iterator_facade<
|
||||||
|
node_iterator
|
||||||
|
, node_base
|
||||||
|
, boost::forward_traversal_tag
|
||||||
|
>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
node_iterator()
|
||||||
|
: m_node(0) {}
|
||||||
|
|
||||||
|
explicit node_iterator(node_base* p)
|
||||||
|
: m_node(p) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class boost::iterator_core_access;
|
||||||
|
|
||||||
|
void increment() { m_node = m_node->next(); }
|
||||||
|
|
||||||
|
bool equal(node_iterator const& other) const
|
||||||
|
{
|
||||||
|
return this->m_node == other.m_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_base& dereference() const { return *m_node; }
|
||||||
|
|
||||||
|
node_base* m_node;
|
||||||
|
};
|
||||||
|
|
||||||
|
Voil<EFBFBD>; a complete and conforming readable, forward-traversal
|
||||||
|
iterator! For a working example of its use, see `this program`__.
|
||||||
|
|
||||||
|
__ ../example/node_iterator1.cpp
|
||||||
|
|
||||||
|
A constant ``node_iterator``
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
.. Sidebar:: Constant and Mutable iterators
|
||||||
|
|
||||||
|
The term **mutable iterator** means an iterator through which
|
||||||
|
the object it references (its "referent") can be modified. A
|
||||||
|
**constant iterator** is one which doesn't allow modification of
|
||||||
|
its referent.
|
||||||
|
|
||||||
|
The words *constant* and *mutable* don't refer to the ability to
|
||||||
|
modify the iterator itself. For example, an ``int const*`` is a
|
||||||
|
non-\ ``const`` *constant iterator*, which can be incremented
|
||||||
|
but doesn't allow modification of its referent, and ``int*
|
||||||
|
const`` is a ``const`` *mutable iterator*, which cannot be
|
||||||
|
modified but which allows modification of its referent.
|
||||||
|
|
||||||
|
Confusing? We agree, but those are the standard terms. It
|
||||||
|
probably doesn't help much that a container's constant iterator
|
||||||
|
is called ``const_iterator``.
|
||||||
|
|
||||||
|
Now, our ``node_iterator`` gives clients access to both ``node``\
|
||||||
|
's ``print(std::ostream&) const`` member function, but also its
|
||||||
|
mutating ``double_me()`` member. If we wanted to build a
|
||||||
|
*constant* ``node_iterator``, we'd only have to make three
|
||||||
|
changes:
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
class const_node_iterator
|
||||||
|
: public boost::iterator_facade<
|
||||||
|
node_iterator
|
||||||
|
, node_base **const**
|
||||||
|
, boost::forward_traversal_tag
|
||||||
|
>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const_node_iterator()
|
||||||
|
: m_node(0) {}
|
||||||
|
|
||||||
|
explicit const_node_iterator(node_base* p)
|
||||||
|
: m_node(p) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class boost::iterator_core_access;
|
||||||
|
|
||||||
|
void increment() { m_node = m_node->next(); }
|
||||||
|
|
||||||
|
bool equal(const_node_iterator const& other) const
|
||||||
|
{
|
||||||
|
return this->m_node == other.m_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_base **const**\ & dereference() const { return \*m_node; }
|
||||||
|
|
||||||
|
node_base **const**\ * m_node;
|
||||||
|
};
|
||||||
|
|
||||||
|
.. Sidebar:: ``const`` and an iterator's ``value_type``
|
||||||
|
|
||||||
|
The C++ standard requires an iterator's ``value_type`` *not* be
|
||||||
|
``const``\ -qualified, so ``iterator_facade`` strips the
|
||||||
|
``const`` from its ``Value`` parameter in order to produce the
|
||||||
|
iterator's ``value_type``. Making the ``Value`` argument
|
||||||
|
``const`` provides a useful hint to ``iterator_facade`` that the
|
||||||
|
iterator is a *constant iterator*, and the default ``Reference``
|
||||||
|
argument will be correct for all lvalue iterators.
|
||||||
|
|
||||||
|
As a matter of fact, ``node_iterator`` and ``const_node_iterator``
|
||||||
|
are so similar that it makes sense to factor the common code out
|
||||||
|
into a template as follows::
|
||||||
|
|
||||||
|
template <class Value>
|
||||||
|
class node_iter
|
||||||
|
: public boost::iterator_facade<
|
||||||
|
node_iter<Value>
|
||||||
|
, Value
|
||||||
|
, boost::forward_traversal_tag
|
||||||
|
>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
node_iter()
|
||||||
|
: m_node(0) {}
|
||||||
|
|
||||||
|
explicit node_iter(Value* p)
|
||||||
|
: m_node(p) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class boost::iterator_core_access;
|
||||||
|
|
||||||
|
bool equal(node_iter<Value> const& other) const
|
||||||
|
{
|
||||||
|
return this->m_node == other.m_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void increment()
|
||||||
|
{ m_node = m_node->next(); }
|
||||||
|
|
||||||
|
Value& dereference() const
|
||||||
|
{ return *m_node; }
|
||||||
|
|
||||||
|
Value* m_node;
|
||||||
|
};
|
||||||
|
typedef node_iter<node_base> node_iterator;
|
||||||
|
typedef node_iter<node_base const> node_const_iterator;
|
||||||
|
|
||||||
|
|
||||||
|
Interoperability
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Our ``const_node_iterator`` works perfectly well on its own, but
|
||||||
|
taken together with ``node_iterator`` it doesn't quite meet
|
||||||
|
expectations. For example, we'd like to be able to pass a
|
||||||
|
``node_iterator`` where a ``node_const_iterator`` was expected,
|
||||||
|
just as you can with ``std::list<int>``\ 's ``iterator`` and
|
||||||
|
``const_iterator``. Furthermore, given a ``node_iterator`` and a
|
||||||
|
``node_const_iterator`` into the same list, we should be able to
|
||||||
|
compare them for equality.
|
||||||
|
|
||||||
|
This expected ability to use two different iterator types together
|
||||||
|
is known as |interoperability|_. Achieving interoperability in
|
||||||
|
our case is as simple as templatizing the ``equal`` function and
|
||||||
|
adding a templatized converting constructor [#broken]_ [#random]_::
|
||||||
|
|
||||||
|
template <class Value>
|
||||||
|
class node_iter
|
||||||
|
: public boost::iterator_facade<
|
||||||
|
node_iter<Value>
|
||||||
|
, Value
|
||||||
|
, boost::forward_traversal_tag
|
||||||
|
>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
node_iter()
|
||||||
|
: m_node(0) {}
|
||||||
|
|
||||||
|
explicit node_iter(Value* p)
|
||||||
|
: m_node(p) {}
|
||||||
|
|
||||||
|
template <class OtherValue>
|
||||||
|
node_iter(node_iter<OtherValue> const& other)
|
||||||
|
: m_node(other.m_node) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class boost::iterator_core_access;
|
||||||
|
template <class> friend class node_iter;
|
||||||
|
|
||||||
|
template <class OtherValue>
|
||||||
|
bool equal(node_iter<OtherValue> const& other) const
|
||||||
|
{
|
||||||
|
return this->m_node == other.m_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void increment()
|
||||||
|
{ m_node = m_node->next(); }
|
||||||
|
|
||||||
|
Value& dereference() const
|
||||||
|
{ return *m_node; }
|
||||||
|
|
||||||
|
Value* m_node;
|
||||||
|
};
|
||||||
|
typedef impl::node_iterator<node_base> node_iterator;
|
||||||
|
typedef impl::node_iterator<node_base const> node_const_iterator;
|
||||||
|
|
||||||
|
.. |interoperability| replace:: **interoperability**
|
||||||
|
.. _interoperability: new-iter-concepts.html#interoperable-iterators-lib-interoperable-iterators
|
||||||
|
|
||||||
|
.. [#broken] If you're using an older compiler and it can't handle
|
||||||
|
this example, see the `example code`__ for workarounds.
|
||||||
|
|
||||||
|
.. [#random] If ``node_iterator`` had been a `random access
|
||||||
|
traversal iterator`_, we'd have had to templatize its
|
||||||
|
``distance_to`` function as well.
|
||||||
|
|
||||||
|
|
||||||
|
__ ../example/node_iterator2.hpp
|
||||||
|
|
||||||
|
You can see an example program which exercises our interoperable
|
||||||
|
iterators `here`__.
|
||||||
|
|
||||||
|
__ ../example/node_iterator2.cpp
|
||||||
|
|
||||||
|
Telling the Truth
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Now ``node_iterator`` and ``node_const_iterator`` behave exactly as
|
||||||
|
you'd expect... almost. We can compare them and we can convert in
|
||||||
|
one direction: from ``node_iterator`` to ``node_const_iterator``.
|
||||||
|
If we try to convert from ``node_const_iterator`` to
|
||||||
|
``node_iterator``, we'll get an error when the converting
|
||||||
|
constructor tries to initialize ``node_iterator``\ 's ``m_node``, a
|
||||||
|
``node*`` with a ``node const*``. So what's the problem?
|
||||||
|
|
||||||
|
The problem is that
|
||||||
|
``boost::``\ |is_convertible|_\ ``<node_const_iterator,node_iterator>::value``
|
||||||
|
will be ``true``, but it should be ``false``. |is_convertible|_
|
||||||
|
lies because it can only see as far as the *declaration* of
|
||||||
|
``node_iter``\ 's converting constructor, but can't look inside at
|
||||||
|
the *definition* to make sure it will compile. A perfect solution
|
||||||
|
would make ``node_iter``\ 's converting constructor disappear when
|
||||||
|
the ``m_node`` conversion would fail.
|
||||||
|
|
||||||
|
.. |is_convertible| replace:: ``is_convertible``
|
||||||
|
.. _is_convertible: ../../type_traits/index.html#relationships
|
||||||
|
|
||||||
|
In fact, that sort of magic is possible using
|
||||||
|
|enable_if|__. By rewriting the converting constructor as
|
||||||
|
follows, we can remove it from the overload set when it's not
|
||||||
|
appropriate::
|
||||||
|
|
||||||
|
#include <boost/type_traits/is_convertible.hpp>
|
||||||
|
#include <boost/utility/enable_if.hpp>
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
template <class OtherValue>
|
||||||
|
node_iter(
|
||||||
|
node_iter<OtherValue> const& other
|
||||||
|
, typename boost::enable_if<
|
||||||
|
boost::is_convertible<OtherValue*,Value*>
|
||||||
|
, enabler
|
||||||
|
>::type = enabler()
|
||||||
|
)
|
||||||
|
: m_node(other.m_node) {}
|
||||||
|
|
||||||
|
.. |enable_if| replace:: ``boost::enable_if``
|
||||||
|
__ ../../utility/enable_if.html
|
||||||
|
|
||||||
|
|
||||||
|
Wrap Up
|
||||||
|
-------
|
||||||
|
|
||||||
|
This concludes our ``iterator_facade`` tutorial, but before you
|
||||||
|
stop reading we urge you to take a look at |iterator_adaptor|__.
|
||||||
|
There's another way to approach writing these iterators which might
|
||||||
|
even be superior.
|
||||||
|
|
||||||
|
.. |iterator_adaptor| replace:: ``iterator_adaptor``
|
||||||
|
__ iterator_adaptor.html
|
||||||
|
|
||||||
|
.. _`iterator traversal concept`: new-iter-concepts.html#iterator-traversal-concepts-lib-iterator-traversal
|
||||||
|
.. _`readable iterator`: new-iter-concepts.html#readable-iterators-lib-readable-iterators
|
||||||
|
.. _`lvalue iterator`: new-iter-concepts.html#lvalue-iterators-lib-lvalue-iterators
|
||||||
|
.. _`single pass iterator`: new-iter-concepts.html#single-pass-iterators-lib-single-pass-iterators
|
||||||
|
.. _`incrementable iterator`: new-iter-concepts.html#incrementable-iterators-lib-incrementable-iterators
|
||||||
|
.. _`forward traversal iterator`: new-iter-concepts.html#forward-traversal-iterators-lib-forward-traversal-iterators
|
||||||
|
.. _`bidirectional traversal iterator`: new-iter-concepts.html#bidirectional-traversal-iterators-lib-bidirectional-traversal-iterators
|
||||||
|
.. _`random access traversal iterator`: new-iter-concepts.html#random-access-traversal-iterators-lib-random-access-traversal-iterators
|
||||||
|
|
16
doc/make_filter_iterator.rst
Executable file
16
doc/make_filter_iterator.rst
Executable file
@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
template <class Predicate, class Iterator>
|
||||||
|
filter_iterator<Predicate,Iterator>
|
||||||
|
make_filter_iterator(Predicate f, Iterator x, Iterator end = Iterator());
|
||||||
|
|
||||||
|
:Returns: filter_iterator<Predicate,Iterator>(f, x, end)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
template <class Predicate, class Iterator>
|
||||||
|
filter_iterator<Predicate,Iterator>
|
||||||
|
make_filter_iterator(Iterator x, Iterator end = Iterator());
|
||||||
|
|
||||||
|
:Returns: filter_iterator<Predicate,Iterator>(x, end)
|
179
doc/pointee.html
Executable file
179
doc/pointee.html
Executable file
@ -0,0 +1,179 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="generator" content="Docutils 0.3.1: http://docutils.sourceforge.net/" />
|
||||||
|
<title>pointee and indirect_reference</title>
|
||||||
|
<meta name="author" content="David Abrahams" />
|
||||||
|
<meta name="organization" content="Boost Consulting" />
|
||||||
|
<meta name="date" content="2004-01-13" />
|
||||||
|
<meta name="copyright" content="Copyright David Abrahams 2004. All rights reserved" />
|
||||||
|
<link rel="stylesheet" href="default.css" type="text/css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="document" id="pointee-and-indirect-reference">
|
||||||
|
<h1 class="title"><tt class="literal"><span class="pre">pointee</span></tt> and <tt class="literal"><span class="pre">indirect_reference</span></tt></h1>
|
||||||
|
<table class="docinfo" frame="void" rules="none">
|
||||||
|
<col class="docinfo-name" />
|
||||||
|
<col class="docinfo-content" />
|
||||||
|
<tbody valign="top">
|
||||||
|
<tr><th class="docinfo-name">Author:</th>
|
||||||
|
<td>David Abrahams</td></tr>
|
||||||
|
<tr><th class="docinfo-name">Contact:</th>
|
||||||
|
<td><a class="first reference" href="mailto:dave@boost-consulting.com">dave@boost-consulting.com</a>, <a class="reference" href="mailto:jsiek@osl.iu.edu">jsiek@osl.iu.edu</a>, <a class="last reference" href="mailto:witt@ive.uni-hannover.de">witt@ive.uni-hannover.de</a></td></tr>
|
||||||
|
<tr><th class="docinfo-name">Organization:</th>
|
||||||
|
<td><a class="first last reference" href="http://www.boost-consulting.com">Boost Consulting</a></td></tr>
|
||||||
|
<tr><th class="docinfo-name">Date:</th>
|
||||||
|
<td>2004-01-13</td></tr>
|
||||||
|
<tr><th class="docinfo-name">Copyright:</th>
|
||||||
|
<td>Copyright David Abrahams 2004. All rights reserved</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<table class="field-list" frame="void" rules="none">
|
||||||
|
<col class="field-name" />
|
||||||
|
<col class="field-body" />
|
||||||
|
<tbody valign="top">
|
||||||
|
<tr class="field"><th class="field-name">abstract:</th><td class="field-body">Provides the capability to deduce the referent types of
|
||||||
|
pointers, smart pointers and iterators in generic code.</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="section" id="overview">
|
||||||
|
<h1><a name="overview">Overview</a></h1>
|
||||||
|
<p>Have you ever wanted to write a generic function that can operate
|
||||||
|
on any kind of dereferenceable object? If you have, you've
|
||||||
|
probably run into the problem of how to determine the type that the
|
||||||
|
object "points at":</p>
|
||||||
|
<pre class="literal-block">
|
||||||
|
template <class Dereferenceable>
|
||||||
|
void f(Dereferenceable p)
|
||||||
|
{
|
||||||
|
<em>what-goes-here?</em> value = *p;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
<div class="section" id="pointee">
|
||||||
|
<h2><a name="pointee"><tt class="literal"><span class="pre">pointee</span></tt></a></h2>
|
||||||
|
<p>It turns out to be impossible to come up with a fully-general
|
||||||
|
algorithm to do determine <em>what-goes-here</em> directly, but it is
|
||||||
|
possible to require that <tt class="literal"><span class="pre">pointee<Dereferenceable>::type</span></tt> is
|
||||||
|
correct. Naturally, <tt class="literal"><span class="pre">pointee</span></tt> has the same difficulty: it can't
|
||||||
|
determine the appropriate <tt class="literal"><span class="pre">::type</span></tt> reliably for all
|
||||||
|
<tt class="literal"><span class="pre">Dereferenceable</span></tt>s, but it makes very good guesses (it works
|
||||||
|
for all pointers, standard and boost smart pointers, and
|
||||||
|
iterators), and when it guesses wrongly, it can be specialized as
|
||||||
|
neccessary:</p>
|
||||||
|
<pre class="literal-block">
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
template <class T>
|
||||||
|
struct pointee<third_party_lib::smart_pointer<T> >
|
||||||
|
{
|
||||||
|
typedef T type;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
<div class="section" id="indirect-reference">
|
||||||
|
<h2><a name="indirect-reference"><tt class="literal"><span class="pre">indirect_reference</span></tt></a></h2>
|
||||||
|
<p><tt class="literal"><span class="pre">indirect_reference<T>::type</span></tt> is rather more specialized than
|
||||||
|
<tt class="literal"><span class="pre">pointee</span></tt>, and is meant to be used to forward the result of
|
||||||
|
dereferencing an object of its argument type. Most dereferenceable
|
||||||
|
types just return a reference to their pointee, but some return
|
||||||
|
proxy references or return the pointee by value. When that
|
||||||
|
information is needed, call on <tt class="literal"><span class="pre">indirect_reference</span></tt>.</p>
|
||||||
|
<p>Both of these templates are essential to the correct functioning of
|
||||||
|
<a class="reference" href="indirect_iterator.html"><tt class="literal"><span class="pre">indirect_iterator</span></tt></a>.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="section" id="reference">
|
||||||
|
<h1><a name="reference">Reference</a></h1>
|
||||||
|
<div class="section" id="id1">
|
||||||
|
<h2><a name="id1"><tt class="literal"><span class="pre">pointee</span></tt></a></h2>
|
||||||
|
<!-- Copyright David Abrahams 2004. Use, modification and distribution is -->
|
||||||
|
<!-- subject to the Boost Software License, Version 1.0. (See accompanying -->
|
||||||
|
<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -->
|
||||||
|
<pre class="literal-block">
|
||||||
|
template <class Dereferenceable>
|
||||||
|
struct pointee
|
||||||
|
{
|
||||||
|
typedef /* see below */ type;
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
<table class="field-list" frame="void" rules="none">
|
||||||
|
<col class="field-name" />
|
||||||
|
<col class="field-body" />
|
||||||
|
<tbody valign="top">
|
||||||
|
<tr class="field"><th class="field-name">Requires:</th><td class="field-body">For an object <tt class="literal"><span class="pre">x</span></tt> of type <tt class="literal"><span class="pre">Dereferenceable</span></tt>, <tt class="literal"><span class="pre">*x</span></tt>
|
||||||
|
is well-formed. If <tt class="literal"><span class="pre">++x</span></tt> is ill-formed it shall neither be
|
||||||
|
ambiguous nor shall it violate access control, and
|
||||||
|
<tt class="literal"><span class="pre">Dereferenceable::element_type</span></tt> shall be an accessible type.
|
||||||
|
Otherwise <tt class="literal"><span class="pre">iterator_traits<Dereferenceable>::value_type</span></tt> shall
|
||||||
|
be well formed. [Note: These requirements need not apply to
|
||||||
|
explicit or partial specializations of <tt class="literal"><span class="pre">pointee</span></tt>]</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p><tt class="literal"><span class="pre">type</span></tt> is determined according to the following algorithm, where
|
||||||
|
<tt class="literal"><span class="pre">x</span></tt> is an object of type <tt class="literal"><span class="pre">Dereferenceable</span></tt>:</p>
|
||||||
|
<pre class="literal-block">
|
||||||
|
if ( ++x is ill-formed )
|
||||||
|
{
|
||||||
|
return ``Dereferenceable::element_type``
|
||||||
|
}
|
||||||
|
else if (``*x`` is a mutable reference to
|
||||||
|
std::iterator_traits<Dereferenceable>::value_type)
|
||||||
|
{
|
||||||
|
return iterator_traits<Dereferenceable>::value_type
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return iterator_traits<Dereferenceable>::value_type const
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
<div class="section" id="id2">
|
||||||
|
<h2><a name="id2"><tt class="literal"><span class="pre">indirect_reference</span></tt></a></h2>
|
||||||
|
<!-- Copyright David Abrahams 2004. Use, modification and distribution is -->
|
||||||
|
<!-- subject to the Boost Software License, Version 1.0. (See accompanying -->
|
||||||
|
<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -->
|
||||||
|
<pre class="literal-block">
|
||||||
|
template <class Dereferenceable>
|
||||||
|
struct indirect_reference
|
||||||
|
{
|
||||||
|
typedef /* see below */ type;
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
<table class="field-list" frame="void" rules="none">
|
||||||
|
<col class="field-name" />
|
||||||
|
<col class="field-body" />
|
||||||
|
<tbody valign="top">
|
||||||
|
<tr class="field"><th class="field-name">Requires:</th><td class="field-body">For an object <tt class="literal"><span class="pre">x</span></tt> of type <tt class="literal"><span class="pre">Dereferenceable</span></tt>, <tt class="literal"><span class="pre">*x</span></tt>
|
||||||
|
is well-formed. If <tt class="literal"><span class="pre">++x</span></tt> is ill-formed it shall neither be
|
||||||
|
ambiguous nor shall it violate access control, and
|
||||||
|
<tt class="literal"><span class="pre">pointee<Dereferenceable>::type&</span></tt> shall be well-formed.
|
||||||
|
Otherwise <tt class="literal"><span class="pre">iterator_traits<Dereferenceable>::reference</span></tt> shall
|
||||||
|
be well formed. [Note: These requirements need not apply to
|
||||||
|
explicit or partial specializations of <tt class="literal"><span class="pre">indirect_reference</span></tt>]</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p><tt class="literal"><span class="pre">type</span></tt> is determined according to the following algorithm, where
|
||||||
|
<tt class="literal"><span class="pre">x</span></tt> is an object of type <tt class="literal"><span class="pre">Dereferenceable</span></tt>:</p>
|
||||||
|
<pre class="literal-block">
|
||||||
|
if ( ++x is ill-formed )
|
||||||
|
return ``pointee<Dereferenceable>::type&``
|
||||||
|
else
|
||||||
|
std::iterator_traits<Dereferenceable>::reference
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr class="footer" />
|
||||||
|
<div class="footer">
|
||||||
|
<a class="reference" href="pointee.rst">View document source</a>.
|
||||||
|
Generated by <a class="reference" href="http://docutils.sourceforge.net/">Docutils</a> from <a class="reference" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> source.
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
84
doc/pointee.rst
Executable file
84
doc/pointee.rst
Executable file
@ -0,0 +1,84 @@
|
|||||||
|
++++++++++++++++++++++++++++++++++++++++
|
||||||
|
``pointee`` and ``indirect_reference``
|
||||||
|
++++++++++++++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
:Author: David Abrahams
|
||||||
|
:Contact: dave@boost-consulting.com, jsiek@osl.iu.edu, witt@ive.uni-hannover.de
|
||||||
|
:organization: `Boost Consulting`_
|
||||||
|
:date: $Date$
|
||||||
|
:copyright: Copyright David Abrahams 2004. All rights reserved
|
||||||
|
|
||||||
|
.. _`Boost Consulting`: http://www.boost-consulting.com
|
||||||
|
|
||||||
|
:abstract: Provides the capability to deduce the referent types of
|
||||||
|
pointers, smart pointers and iterators in generic code.
|
||||||
|
|
||||||
|
Overview
|
||||||
|
========
|
||||||
|
|
||||||
|
Have you ever wanted to write a generic function that can operate
|
||||||
|
on any kind of dereferenceable object? If you have, you've
|
||||||
|
probably run into the problem of how to determine the type that the
|
||||||
|
object "points at":
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
template <class Dereferenceable>
|
||||||
|
void f(Dereferenceable p)
|
||||||
|
{
|
||||||
|
*what-goes-here?* value = \*p;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
``pointee``
|
||||||
|
-----------
|
||||||
|
|
||||||
|
It turns out to be impossible to come up with a fully-general
|
||||||
|
algorithm to do determine *what-goes-here* directly, but it is
|
||||||
|
possible to require that ``pointee<Dereferenceable>::type`` is
|
||||||
|
correct. Naturally, ``pointee`` has the same difficulty: it can't
|
||||||
|
determine the appropriate ``::type`` reliably for all
|
||||||
|
``Dereferenceable``\ s, but it makes very good guesses (it works
|
||||||
|
for all pointers, standard and boost smart pointers, and
|
||||||
|
iterators), and when it guesses wrongly, it can be specialized as
|
||||||
|
neccessary::
|
||||||
|
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
template <class T>
|
||||||
|
struct pointee<third_party_lib::smart_pointer<T> >
|
||||||
|
{
|
||||||
|
typedef T type;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
``indirect_reference``
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
``indirect_reference<T>::type`` is rather more specialized than
|
||||||
|
``pointee``, and is meant to be used to forward the result of
|
||||||
|
dereferencing an object of its argument type. Most dereferenceable
|
||||||
|
types just return a reference to their pointee, but some return
|
||||||
|
proxy references or return the pointee by value. When that
|
||||||
|
information is needed, call on ``indirect_reference``.
|
||||||
|
|
||||||
|
Both of these templates are essential to the correct functioning of
|
||||||
|
|indirect_iterator|_.
|
||||||
|
|
||||||
|
.. |indirect_iterator| replace:: ``indirect_iterator``
|
||||||
|
.. _indirect_iterator: indirect_iterator.html
|
||||||
|
|
||||||
|
Reference
|
||||||
|
=========
|
||||||
|
|
||||||
|
``pointee``
|
||||||
|
-----------
|
||||||
|
|
||||||
|
.. include:: pointee_ref.rst
|
||||||
|
|
||||||
|
``indirect_reference``
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
.. include:: indirect_reference_ref.rst
|
||||||
|
|
38
doc/pointee_ref.rst
Executable file
38
doc/pointee_ref.rst
Executable file
@ -0,0 +1,38 @@
|
|||||||
|
.. Copyright David Abrahams 2004. Use, modification and distribution is
|
||||||
|
.. subject to the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
template <class Dereferenceable>
|
||||||
|
struct pointee
|
||||||
|
{
|
||||||
|
typedef /* see below */ type;
|
||||||
|
};
|
||||||
|
|
||||||
|
:Requires: For an object ``x`` of type ``Dereferenceable``, ``*x``
|
||||||
|
is well-formed. If ``++x`` is ill-formed it shall neither be
|
||||||
|
ambiguous nor shall it violate access control, and
|
||||||
|
``Dereferenceable::element_type`` shall be an accessible type.
|
||||||
|
Otherwise ``iterator_traits<Dereferenceable>::value_type`` shall
|
||||||
|
be well formed. [Note: These requirements need not apply to
|
||||||
|
explicit or partial specializations of ``pointee``]
|
||||||
|
|
||||||
|
``type`` is determined according to the following algorithm, where
|
||||||
|
``x`` is an object of type ``Dereferenceable``::
|
||||||
|
|
||||||
|
if ( ++x is ill-formed )
|
||||||
|
{
|
||||||
|
return ``Dereferenceable::element_type``
|
||||||
|
}
|
||||||
|
else if (``*x`` is a mutable reference to
|
||||||
|
std::iterator_traits<Dereferenceable>::value_type)
|
||||||
|
{
|
||||||
|
return iterator_traits<Dereferenceable>::value_type
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return iterator_traits<Dereferenceable>::value_type const
|
||||||
|
}
|
||||||
|
|
||||||
|
|
7
doc/rst2html
Executable file
7
doc/rst2html
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
PYTHONPATH="c:/src/docutils/docutils;c:/src/docutils/docutils/extras"
|
||||||
|
export PYTHONPATH
|
||||||
|
python c:/src/docutils/docutils/tools/html.py -gs $1 `echo $1 | sed 's/\(.*\)\..*/\1.html/'`
|
||||||
|
|
||||||
|
|
||||||
|
|
29
doc/scanrst.py
Normal file
29
doc/scanrst.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Copyright David Abrahams 2004. Use, modification and distribution is
|
||||||
|
# subject to the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
# This script accepts a list of .rst files to be processed and
|
||||||
|
# generates Makefile dependencies for .html and .rst files to stdout.
|
||||||
|
import os,sys
|
||||||
|
import re
|
||||||
|
|
||||||
|
include = re.compile(r' *\.\. +(include|image):: +(.*)', re.MULTILINE)
|
||||||
|
|
||||||
|
def deps(path, found):
|
||||||
|
dir = os.path.split(path)[0]
|
||||||
|
for m in re.findall(include, open(path).read()):
|
||||||
|
|
||||||
|
dependency = os.path.normpath(os.path.join(dir,m[1]))
|
||||||
|
if dependency not in found:
|
||||||
|
found[dependency] = 1
|
||||||
|
|
||||||
|
if m[0] == 'include':
|
||||||
|
deps(dependency, found)
|
||||||
|
|
||||||
|
return found
|
||||||
|
|
||||||
|
for file in sys.argv[1:]:
|
||||||
|
found = deps(file, {})
|
||||||
|
if found:
|
||||||
|
base = os.path.splitext(os.path.basename(file))[0]
|
||||||
|
print '%s.tex %s.html: %s' % (base, base, ' '.join(found.keys()))
|
Reference in New Issue
Block a user