added a bunch for the specialized adaptors,

also filled out the facade and adaptor sections


[SVN r1181]
This commit is contained in:
Jeremy Siek
2003-04-25 04:51:32 +00:00
parent 80b70a675d
commit 1397e144c1
2 changed files with 524 additions and 65 deletions

View File

@@ -6,7 +6,7 @@
:Contact: dave@boost-consulting.com, jsiek@osl.iu.edu, witt@ive.uni-hannover.de :Contact: dave@boost-consulting.com, jsiek@osl.iu.edu, witt@ive.uni-hannover.de
:organization: `Boost Consulting`_, Indiana University `Open Systems Lab`_, University of Hanover `Institute for Transport Railway Operation and Construction`_ :organization: `Boost Consulting`_, Indiana University `Open Systems Lab`_, University of Hanover `Institute for Transport Railway Operation and Construction`_
:date: $Date$ :date: $Date$
:Number: N1476=03-0059
:copyright: Copyright Dave Abrahams, Jeremy Siek, and Thomas Witt 2003. All rights reserved :copyright: Copyright Dave Abrahams, Jeremy Siek, and Thomas Witt 2003. All rights reserved
.. _`Boost Consulting`: http://www.boost-consulting.com .. _`Boost Consulting`: http://www.boost-consulting.com
@@ -14,7 +14,7 @@
.. _`Institute for Transport Railway Operation and Construction`: http://www.ive.uni-hannover.de .. _`Institute for Transport Railway Operation and Construction`: http://www.ive.uni-hannover.de
:abstract: We propose a set of class templates that help programmers :abstract: We propose a set of class templates that help programmers
build standard-conforming iterators and to build iterators build standard-conforming iterators and iterators
that adapt other iterators. that adapt other iterators.
.. contents:: Table of Contents .. contents:: Table of Contents
@@ -121,12 +121,12 @@ Iterator Concepts.
Interoperability Interoperability
================ ================
The question of iterator interoperability is poorly adressed in the current standard. The question of iterator interoperability is poorly adressed in the
There are currently two defect reports that are concerned with interoperability current standard. There are currently two defect reports that are
issues. concerned with interoperability issues.
Issue `179`_ concerns the fact that mutable container iterator types Issue `179`_ concerns the fact that mutable container iterator types
are only required to be convertible the corresponding constant are only required to be convertible to the corresponding constant
iterator types, but objects of these types are not required to iterator types, but objects of these types are not required to
interoperate in comparison or subtraction expressions. This situation interoperate in comparison or subtraction expressions. This situation
is tedious in practice and out of line with the way built in types is tedious in practice and out of line with the way built in types
@@ -161,7 +161,8 @@ identified the following core behaviors for iterators:
In addition to the behaviors listed above, the core interface elements In addition to the behaviors listed above, the core interface elements
include the associated types exposed through iterator traits: include the associated types exposed through iterator traits:
``value_type``, ``reference``, ``pointer``, and ``iterator_category``. ``value_type``, ``reference``, ``pointer``, ``difference_type``, and
``iterator_category``.
Iterator facade uses the Curiously Recurring Template Pattern (CRTP) Iterator facade uses the Curiously Recurring Template Pattern (CRTP)
[Cop95]_ so that the user can specifiy the behaviour of [Cop95]_ so that the user can specifiy the behaviour of
@@ -222,43 +223,47 @@ interoperable with X.
| | |>= c``. | | | | |>= c``. | |
+----------------------------------------+----------------------------------------+-------------------------------------------------+-------------------------------------------+ +----------------------------------------+----------------------------------------+-------------------------------------------------+-------------------------------------------+
.. Should we add a comment that a zero overhead implementation of iterator_facade .. Should we add a comment that a zero overhead implementation of iterator_facade
is possible with proper inlining? is possible with proper inlining?
.. Would this be a good place to talk about constructors? -JGS
Iterator Core Access Iterator Core Access
==================== ====================
``iterator_facade`` and the operator implementations need to be able ``iterator_facade`` and the operator implementations need to be able
to access the core interface member functions in the derived class. to access the core member functions in the derived class. Making the
Making the core interface member funtions public would expose an core member funtions public would expose an implementation detail to
implementation detail to the user. This proposal frees the public the user. This proposal frees the public interface of the derived
interface of the derived iterator type from any implementation detail. iterator type from any implementation detail.
Preventing direct access to the core interface has two advantages. Preventing direct access to the core member functions has two
First, there is no possibility for the user to accidently use a member advantages. First, there is no possibility for the user to accidently
function of the iterator when a member of the value_type was intended. use a member function of the iterator when a member of the value_type
This has been an issue with smart pointer implementations in the past. was intended. This has been an issue with smart pointer
The second and main advantage is that library implementers can freely implementations in the past. The second and main advantage is that
exchange a hand-rolled iterator implementation for one based on library implementers can freely exchange a hand-rolled iterator
``iterator_facade`` without fear of breaking code that was accessing implementation for one based on ``iterator_facade`` without fear of
the public core interface directly. breaking code that was accessing the public core member functions
directly.
In a naive implementation, keeping the derived class' core interface In a naive implementation, keeping the derived class' core member
private would require it to grant friendship to ``iterator_facade`` functions private would require it to grant friendship to
and each of the seven operators. In order to reduce the burden of ``iterator_facade`` and each of the seven operators. In order to
limiting access, this proposal provides ``iterator_core_access``, a reduce the burden of limiting access, this proposal provides
class that acts as a gateway to the core interface in the derived ``iterator_core_access``, a class that acts as a gateway to the core
iterator class. The author of the derived class only needs to grant member functions in the derived iterator class. The author of the
friendship to ``iterator_core_access`` to make his core interface derived class only needs to grant friendship to
available to the library. ``iterator_core_access`` to make his core member functions available
to the library.
``iterator_core_access`` would be typically implemented as an empty ``iterator_core_access`` would be typically implemented as an empty
class containing only static member functions which invoke the class containing only static member functions which invoke the
iterator core interface. There is, however, no need to standardize the iterator core member functions. There is, however, no need to
gateway protocol. standardize the gateway protocol.
It is important to note that ``iterator_core_access`` does not open a It is important to note that ``iterator_core_access`` does not open a
safety loophole, as every function in the core interface preserves the safety loophole, as every core member function preserves the
invariants of the iterator. invariants of the iterator.
Iterator Adaptor Iterator Adaptor
@@ -279,7 +284,11 @@ instance of the ``Base`` type, which it stores as a member.
The user of ``iterator_adaptor`` creates a class derived from an The user of ``iterator_adaptor`` creates a class derived from an
instantiation of ``iterator_adaptor`` and then selectively overrides instantiation of ``iterator_adaptor`` and then selectively overrides
some of the core operations by implementing the (non-virtual) member some of the core operations by implementing the (non-virtual) member
functions described in the table above. functions described in the table above. The ``Base`` type
need not meet the full requirements for an iterator. It need
only support the operations that are not overriden by the
users derived class.
.. In addition, the derived .. In addition, the derived
class will typically need to define some constructors. class will typically need to define some constructors.
@@ -321,8 +330,8 @@ which were easily implemented using ``iterator_adaptor``:
Based on examples in the Boost library, users have generated many new Based on examples in the Boost library, users have generated many new
adaptors, among them a permutation adaptor which applies some adaptors, among them a permutation adaptor which applies some
permutation to a RandomAccessIterator, and a strided adaptor, which permutation to a Random Access Iterator, and a strided adaptor, which
adapts a RandomAccessIterator by multiplying its unit of motion by a adapts a Random Access Iterator by multiplying its unit of motion by a
constant factor. In addition, the Boost Graph Library (BGL) uses constant factor. In addition, the Boost Graph Library (BGL) uses
iterator adaptors to adapt other graph libraries, such as LEDA [10] iterator adaptors to adapt other graph libraries, such as LEDA [10]
and Stanford GraphBase [8], to the BGL interface (which requires C++ and Stanford GraphBase [8], to the BGL interface (which requires C++
@@ -332,51 +341,95 @@ Standard compliant iterators).
Proposed Text Proposed Text
=============== ===============
Header ``<iterator_helper>`` synopsis [lib.iterator.helper.synopsis]
=======================================================================
.. How's that for a name for the header? -JGS
.. Also, below I changed "not_specified" to the user-centric "use_default" -JGS
:: ::
struct not_specified { }; struct use_default { };
struct iterator_core_access { /* implementation detail */ }; struct iterator_core_access { /* implementation detail */ };
template < template <
class Derived class Derived
, class Value = not_specified , class Value = use_default
, class Category = not_specified , class Category = use_default
, class Reference = not_specified , class Reference = use_default
, class Pointer = not_specified , class Pointer = use_default
, class Difference = not_specified , class Difference = use_default
> >
class iterator_facade; class iterator_facade;
template < template <
class Derived class Derived
, class Base , class Base
, class Value = not_specified , class Value = use_default
, class Category = not_specified , class Category = use_default
, class Reference = not_specified , class Reference = use_default
, class Pointer = not_specified , class Pointer = use_default
, class Difference = not_specified , class Difference = use_default
> >
class iterator_adaptor; class iterator_adaptor;
template <
class Iterator
, class Value = use_default
, class Category = use_default
, class Reference = use_default
, class Pointer = use_default
, class Difference = use_default
>
class indirect_iterator;
template <class Iterator>
class reverse_iterator;
template <class AdaptableUnaryFunction, class Iterator>
class transform_iterator;
template <class Predicate, class Iterator>
class filter_iterator;
template <
class Incrementable,
class Category = use_default,
class Difference = use_default
>
class counting_iterator
template <class UnaryFunction>
class function_output_iterator;
``iterator_facade``
=================== Iterator facade [lib.iterator.facade]
=====================================
The iterator requirements define a rich interface, containing many
redundant operators, so that using iterators is convenient. The
``iterator_facade`` class template makes it easier to create iterators
by implementing the rich interface of standard iterators in terms of a
few core functions. The user of ``iterator_facade`` derives his
iterator class from an instantiation of ``iterator_facade`` and
defines member functions implementing the core behaviors.
Template class ``iterator_facade``
----------------------------------
:: ::
template < template <
class Derived class Derived
, class Value = not_specified , class Value = use_default
, class Category = not_specified , class Category = use_default
, class Reference = not_specified , class Reference = use_default
, class Pointer = not_specified , class Pointer = use_default
, class Difference = not_specified , class Difference = use_default
> >
class iterator_facade { class iterator_facade {
public: public:
@@ -387,8 +440,8 @@ Standard compliant iterators).
typedef ... iterator_category; typedef ... iterator_category;
reference operator*() const; reference operator*() const;
<see details> operator->() const; /* see details */ operator->() const;
<see details> operator[](difference_type n) const; /* see details */ operator[](difference_type n) const;
Derived& operator++(); Derived& operator++();
Derived operator++(int); Derived operator++(int);
Derived& operator--(); Derived& operator--();
@@ -456,6 +509,63 @@ Standard compliant iterators).
.. nothing .. nothing
``iterator_facade`` requirements
--------------------------------
The ``Derived`` template parameter must be the class deriving from
``iterator_facade``.
.. We need to describe how the defaults work and what
the typedefs come out to. -JGS
The following table describes the requirements on the type deriving
from the ``iterator_facade``. The expressions listed in the table are
required to be valid depending on the category of the derived iterator
type.
In the table below, ``X`` is the derived iterator type, ``a`` is an
object of type ``X``, ``b`` and ``c`` are objects of type ``const X``,
``n`` is an object of ``X::difference_type``, ``y`` is a constant
object of a single pass iterator type interoperable with X, and ``z``
is a constant object of a random access traversal iterator type
interoperable with X.
+----------------------------------------+----------------------------------------+-------------------------------------------------+-------------------------------------------+
| Expression | Return Type | Assertion/Note/Precondition/Postcondition | Required to implement Iterator Concept(s) |
| | | | |
+========================================+========================================+=================================================+===========================================+
| ``c.dereference()`` | ``X::reference`` | | Readable Iterator, Writable Iterator |
+----------------------------------------+----------------------------------------+-------------------------------------------------+-------------------------------------------+
| ``c.equal(b)`` | convertible to bool |true iff ``b`` and ``c`` are equivalent. | Single Pass Iterator |
+----------------------------------------+----------------------------------------+-------------------------------------------------+-------------------------------------------+
| ``c.equal(y)`` | convertible to bool |true iff ``c`` and ``y`` refer to the same | Single Pass Iterator |
| | |position. Implements ``c == y`` and ``c != y``. | |
+----------------------------------------+----------------------------------------+-------------------------------------------------+-------------------------------------------+
| ``a.advance(n)`` | unused | | Random Access Traversal Iterator |
+----------------------------------------+----------------------------------------+-------------------------------------------------+-------------------------------------------+
| ``a.increment()`` | unused | | Incrementable Iterator |
+----------------------------------------+----------------------------------------+-------------------------------------------------+-------------------------------------------+
| ``a.decrement()`` | unused | | Bidirectional Traversal Iterator |
+----------------------------------------+----------------------------------------+-------------------------------------------------+-------------------------------------------+
| ``c.distance_to(b)`` | convertible to X::difference_type | equivalent to ``distance(c, b)`` | Random Access Traversal Iterator |
+----------------------------------------+----------------------------------------+-------------------------------------------------+-------------------------------------------+
| ``c.distance_to(z)`` | convertible to X::difference_type |equivalent to ``distance(c, z)``. Implements ``c| Random Access Traversal Iterator |
| | |- z``, ``c < z``, ``c <= z``, ``c > z``, and ``c | |
| | |>= c``. | |
+----------------------------------------+----------------------------------------+-------------------------------------------------+-------------------------------------------+
.. We should explain more about how the
functions in the interface of iterator_facade
are there conditionally. -JGS
``iterator_facade`` operations
------------------------------
``reference operator*() const;`` ``reference operator*() const;``
:Returns: ``static_cast<Derived const*>(this)->dereference();`` :Returns: ``static_cast<Derived const*>(this)->dereference();``
@@ -544,19 +654,50 @@ Standard compliant iterators).
:Complexity: :Complexity:
``iterator_adaptor`` Iterator adaptor [lib.iterator.adaptor]
==================== =======================================
A common pattern of iterator construction is the adaptation of one
iterator to form a new one. The functionality of an iterator is
composed of four orthogonal aspects: traversal, indirection, equality
comparison and distance measurement. Adapting an old iterator to
create a new one often saves work because one can reuse one aspect of
functionality while redefining the other. For example, the Standard
provides ``reverse_iterator``, which adapts any Bidirectional Iterator
by inverting its direction of traversal.
The ``iterator_adaptor`` class template fulfills the need for
constructing adaptors. Instantiations of ``iterator_adaptor`` serve
as a base classes for new iterators, providing the default behaviour
of forwarding all operations to the underlying iterator. The deriving
class can selectively replace these features in the derived iterator
class.
The ``iterator_adaptor`` class template adapts a ``Base`` type to
create a new iterator ("base" here means the type being adapted) .
The ``iterator_adaptor`` forwards all operations to an instance of the
``Base`` type, which it stores as a member. The user of
``iterator_adaptor`` creates a class derived from an instantiation of
``iterator_adaptor`` and then selectively overrides some of the core
operations by implementing the (non-virtual) member functions
described in [lib.iterator.facade]. The ``Base`` type need not meet
the full requirements for an iterator. It need only support the
operations that are not overriden by the users derived class.
Template class ``iterator_adaptor``
-----------------------------------
:: ::
template < template <
class Derived class Derived
, class Base , class Base
, class Value = not_specified , class Value = use_default
, class Category = not_specified , class Category = use_default
, class Reference = not_specified , class Reference = use_default
, class Pointer = not_specified , class Pointer = use_default
, class Difference = not_specified , class Difference = use_default
> >
class iterator_adaptor : public iterator_facade<Derived, /*impl detail ...*/> { class iterator_adaptor : public iterator_facade<Derived, /*impl detail ...*/> {
public: public:
@@ -566,8 +707,326 @@ Standard compliant iterators).
}; };
``iterator_adaptor`` requirements
---------------------------------
Write me.
.. Make sure to mention that this words for both old and new
style iterators. -JGS
Specialized adaptors [lib.iterator.special.adaptors]
====================================================
Indirect iterator
-----------------
The indirect iterator adapts an iterator by applying an *extra*
dereference inside of ``operator*()``. For example, this iterator
adaptor makes it possible to view a container of pointers
(e.g. ``list<foo*>``) as if it were a container of the pointed-to type
(e.g. ``list<foo>``) .
Template class ``indirect_iterator``
++++++++++++++++++++++++++++++++++++
::
template <
class Iterator
, class Value = use_default
, class Category = use_default
, class Reference = use_default
, class Pointer = use_default
, class Difference = use_default
>
class indirect_iterator
: public iterator_adaptor</* see discussion */>
{
typedef iterator_adaptor</* see discussion */> super_t;
friend class iterator_core_access;
public:
indirect_iterator() {}
indirect_iterator(Iterator iter)
: super_t(iter) {}
template <
class Iterator2, class Value2, class Category2
, class Reference2, class Pointer2, class Difference2
>
indirect_iterator(
indirect_iterator<
Iterator2, Value2, Category2, Reference2, Pointer2, Difference2
> const& y
, typename enable_if_convertible<Iterator2, Iterator>::type* = 0
)
: super_t(y.base())
{}
private:
typename super_t::reference dereference() const
{
return **this->base();
}
};
``indirect_iterator`` requirements
++++++++++++++++++++++++++++++++++
The ``value_type`` of the ``Iterator`` template parameter should
itself be dereferenceable. The return type of the ``operator*`` for
the ``value_type`` must be the same type as the ``Reference`` template
parameter. The ``Value`` template parameter will be the ``value_type``
for the ``indirect_iterator``, unless ``Value`` is const. If ``Value``
is ``const X``, then ``value_type`` will be *non-* ``const X``. The
default for ``Value`` is
::
iterator_traits< iterator_traits<Iterator>::value_type >::value_type
If the default is used for ``Value``, then there must be a valid
specialization of ``iterator_traits`` for the value type of the base
iterator.
The ``Reference`` parameter will be the ``reference`` type of the
``indirect_iterator``. The default is ``Value&``.
The ``Pointer`` parameter will be the ``pointer`` type of the
``indirect_iterator``. The default is ``Value*``.
The ``Category`` parameter is the ``iterator_category`` type for the
``indirect_iterator``. The default is
``iterator_traits<Iterator>::iterator_category``.
The indirect iterator will model whichever standard iterator concepts
are modeled by the base iterator. For example, if the base iterator is
a model of Random Access Traversal Iterator then so is the resulting
indirect iterator.
Reverse iterator
----------------
The reverse iterator adaptor flips the direction of a base iterator's
motion. Invoking ``operator++()`` moves the base iterator backward and
invoking ``operator--()`` moves the base iterator forward. The Boost
reverse iterator adaptor is better to use than the
``std::reverse_iterator`` class in situations where pairs of
mutable/constant iterators are needed (e.g., in containers) because
comparisons and conversions between the mutable and const versions are
implemented correctly.
Template class ``reverse_iterator``
+++++++++++++++++++++++++++++++++++
::
template <class Iterator>
class reverse_iterator :
public iterator_adaptor< reverse_iterator<Iterator>, Iterator >
{
typedef iterator_adaptor< reverse_iterator<Iterator>, Iterator > super_t;
friend class iterator_core_access;
public:
reverse_iterator() {}
explicit reverse_iterator(Iterator x)
: super_t(x) {}
template<class OtherIterator>
reverse_iterator(
reverse_iterator<OtherIterator> const& r
, typename enable_if_convertible<OtherIterator, Iterator>::type* = 0
)
: super_t(r.base())
{}
private: /* exposition */
typename super_t::reference dereference() const { return *prior(this->base()); }
void increment() { super_t::decrement(); }
void decrement() { super_t::increment(); }
void advance(typename super_t::difference_type n)
{
super_t::advance(-n);
}
template <class OtherIterator>
typename super_t::difference_type
distance_to(reverse_iterator<OtherIterator> const& y) const
{
return -super_t::distance_to(y);
}
};
``reverse_iterator`` requirements
+++++++++++++++++++++++++++++++++
The base iterator must be a model of Bidirectional Traversal
Iterator. The reverse iterator will model whichever standard iterator
concepts are modeled by the base iterator. For example, if the base
iterator is a model of Random Access Traversal Iterator then so is the
resulting reverse iterator.
Transform iterator
------------------
The transform iterator adapts an iterator by applying some function
object to the result of dereferencing the iterator. In other words,
the ``operator*`` of the transform iterator first dereferences the
base iterator, passes the result of this to the function object, and
then returns the result.
Template class ``transform_iterator``
+++++++++++++++++++++++++++++++++++++
::
template <class AdaptableUnaryFunction, class Iterator>
class transform_iterator
: public iterator_adaptor</* see discussion */>
{
typedef iterator_adaptor</* see discussion */> super_t;
friend class iterator_core_access;
public:
transform_iterator() { }
transform_iterator(Iterator const& x, AdaptableUnaryFunction f)
: super_t(x), m_f(f) { }
template<class OtherIterator>
transform_iterator(
transform_iterator<AdaptableUnaryFunction, OtherIterator> const& t
, typename enable_if_convertible<OtherIterator, Iterator>::type* = 0
)
: super_t(t.base()), m_f(t.functor()) {}
AdaptableUnaryFunction functor() const
{ return m_f; }
private: /* exposition */
typename super_t::value_type dereference() const
{ return m_f(super_t::dereference()); }
AdaptableUnaryFunction m_f;
};
``transform_iterator`` requirements
+++++++++++++++++++++++++++++++++++
Write me. Use ``result_of``?
Filter iterator
---------------
The filter iterator adaptor creates a view of an iterator range in
which some elements of the range are skipped over. A predicate
function object controls which elements are skipped. When the
predicate is applied to an element, if it returns ``true`` then the
element is retained and if it returns ``false`` then the element is
skipped over.
Template class ``filter_iterator``
++++++++++++++++++++++++++++++++++
::
template <class Predicate, class Iterator>
class filter_iterator
: public iterator_adaptor<
filter_iterator<Predicate, Iterator>, Iterator
, use_default
, /* see details */
>
{
public:
filter_iterator() { }
filter_iterator(Predicate f, Iterator x, Iterator end = Iterator());
filter_iterator(Iterator x, Iterator end = Iterator());
template<class OtherIterator>
filter_iterator(
filter_iterator<Predicate, OtherIterator> const& t
, typename enable_if_convertible<OtherIterator, Iterator>::type* = 0
);
Predicate predicate() const;
Iterator end() const;
};
Counting iterator
-----------------
Template class ``counting_iterator``
++++++++++++++++++++++++++++++++++++
::
template <class Incrementable, class Category = not_specified, class Difference = not_specified>
class counting_iterator
: public iterator_adaptor</* see details */>
{
typedef iterator_adaptor</* see details */> super_t;
friend class iterator_core_access;
public:
counting_iterator();
counting_iterator(counting_iterator const& rhs);
counting_iterator(Incrementable x);
};
Function output iterator
------------------------
The function output iterator adaptor makes it easier to create custom
output iterators. The adaptor takes a unary function and creates a
model of Output Iterator. Each item assigned to the output iterator is
passed as an argument to the unary function. The motivation for this
iterator is that creating a conforming output iterator is non-trivial,
particularly because the proper implementation usually requires a
proxy object.
Template class ``function_output_iterator``
+++++++++++++++++++++++++++++++++++++++++++
::
template <class UnaryFunction>
class function_output_iterator {
public:
typedef std::output_iterator_tag iterator_category;
typedef void value_type;
typedef void difference_type;
typedef void pointer;
typedef void reference;
explicit function_output_iterator(const UnaryFunction& f = UnaryFunction())
: m_f(f) {}
struct output_proxy {
output_proxy(UnaryFunction& f);
template <class T> output_proxy& operator=(const T& value);
};
output_proxy operator*();
function_output_iterator& operator++();
function_output_iterator& operator++(int);
};
.. [Cop95] [Coplien, 1995] Coplien, J., Curiously Recurring Template .. [Cop95] [Coplien, 1995] Coplien, J., Curiously Recurring Template
Patterns, C ++Report, February 1995, pp. 24-27. Patterns, C++ Report, February 1995, pp. 24-27.

View File

@@ -230,7 +230,7 @@ combined into a single type using the following `iterator_tag` class.
:: ::
template <class AccessTag, class TraversalTag> template <class AccessTag, class TraversalTag>
struct iterator_tag : appropriate old category struct iterator_tag : /* appropriate old category */
{ {
typedef AccessTag access; typedef AccessTag access;
typedef TraversalTag traversal; typedef TraversalTag traversal;
@@ -530,7 +530,7 @@ Addition to [lib.iterator.synopsis]
template <class Iterator> struct traversal_category; template <class Iterator> struct traversal_category;
template <class AccessTag, class TraversalTag> template <class AccessTag, class TraversalTag>
struct iterator_tag : appropriate old category { struct iterator_tag : /* appropriate old category */ {
typedef AccessTag access; typedef AccessTag access;
typedef TraversalTag traversal; typedef TraversalTag traversal;
}; };