++++++++++++++++++++++ New Iterator Concepts ++++++++++++++++++++++ :Author: David Abrahams, Jeremy Siek, Thomas Witt :Contact: dave@boost-consulting.com, jsiek@osl.iu.edu, witt@acm.org :organization: `Boost Consulting`_, Indiana University `Open Systems Lab`_, University of Hanover `Institute for Transport Railway Operation and Construction`_ :date: $Date$ :Number: N1531=03-0114 :copyright: Copyright David Abrahams, Jeremy Siek, and Thomas Witt 2003. All rights reserved .. _`Boost Consulting`: http://www.boost-consulting.com .. _`Open Systems Lab`: http://www.osl.iu.edu .. _`Institute for Transport Railway Operation and Construction`: http://www.ive.uni-hannover.de :Abstract: We propose a new system of iterator concepts that treat access and positioning independently. This allows the concepts to more closely match the requirements of algorithms and provides better categorizations of iterators that are used in practice. This proposal is a revision of paper n1297_ and n1477_. .. contents:: Table of Contents .. _n1297: http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2001/n1297.html .. _n1477: http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1477.html ============ Motivation ============ The standard iterator categories and requirements are flawed because they use a single hierarchy of concepts to address two orthogonal issues: *iterator traversal* and *value access*. As a result, many algorithms with requirements expressed in terms of the iterator categories are too strict. Also, many real-world iterators can not be accurately categorized. A proxy-based iterator with random-access traversal, for example, may only legally have a category of "input iterator", so generic algorithms are unable to take advantage of its random-access capabilities. The current iterator concept hierarchy is geared towards iterator traversal (hence the category names), while requirements that address value access sneak in at various places. The following table gives a summary of the current value access requirements in the iterator categories. +------------------------------------------------------------------------------+ |Value Access Requirements in Existing Iterator Categories | +========================+=====================================================+ |Output Iterator |``*i = a`` | +------------------------+-----------------------------------------------------+ |Input Iterator |``*i`` is convertible to ``T`` | +------------------------+-----------------------------------------------------+ |Forward Iterator |``*i`` is ``T&`` (or ``const T&`` once `issue 200`_ | | |is resolved) | +------------------------+-----------------------------------------------------+ |Random Access Iterator |``i[n]`` is convertible to ``T`` (also ``i[n] = t`` | | |is required for mutable iterators once `issue 299`_ | | |is resolved) | +------------------------+-----------------------------------------------------+ .. _issue 200: http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/lwg-active.html#200 .. _issue 299: http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/lwg-active.html#299 Because iterator traversal and value access are mixed together in a single hierarchy, many useful iterators can not be appropriately categorized. For example, ``vector::iterator`` is almost a random access iterator, but the return type is not ``bool&`` (see `issue 96`_ and Herb Sutter's paper J16/99-0008 = WG21 N1185). Therefore, the iterators of ``vector`` only meet the requirements of input iterator and output iterator. This is so nonintuitive that the C++ standard contradicts itself on this point. In paragraph 23.2.4/1 it says that a ``vector`` is a sequence that supports random access iterators. .. _issue 96: http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/lwg-active.html#96 Another difficult-to-categorize iterator is the transform iterator, an adaptor which applies a unary function object to the dereferenced value of the some underlying iterator (see `transform_iterator`_). For unary functions such as ``times``, the return type of ``operator*`` clearly needs to be the ``result_type`` of the function object, which is typically not a reference. Because random access iterators are required to return lvalues from ``operator*``, if you wrap ``int*`` with a transform iterator, you do not get a random access iterator as might be expected, but an input iterator. .. _`transform_iterator`: http://www.boost.org/libs/utility/transform_iterator.htm A third example is found in the vertex and edge iterators of the `Boost Graph Library`_. These iterators return vertex and edge descriptors, which are lightweight handles created on-the-fly. They must be returned by-value. As a result, their current standard iterator category is ``input_iterator_tag``, which means that, strictly speaking, you could not use these iterators with algorithms like ``min_element()``. As a temporary solution, the concept `Multi-Pass Input Iterator`_ was introduced to describe the vertex and edge descriptors, but as the design notes for the concept suggest, a better solution is needed. .. _Boost Graph Library: http://www.boost.org/libs/graph/doc/table_of_contents.html .. _Multi-Pass Input Iterator: http://www.boost.org/libs/utility/MultiPassInputIterator.html In short, there are many useful iterators that do not fit into the current standard iterator categories. As a result, the following bad things happen: - Iterators are often mis-categorized. - Algorithm requirements are more strict than necessary, because they cannot separate the need for random access or bidirectional traversal from the need for a true reference return type. ======================== Impact on the Standard ======================== The new iterator concepts are backward-compatible with the old iterator requirements, and old iterators are forward-compatible with the new iterator concepts. That is to say, iterators that satisfy the old requirements also satisfy appropriate concepts in the new system, and iterators modeling the new concepts will automatically satisfy the appropriate old requirements. .. I think we need to say something about the resolution to allow convertibility to any of the old-style tags as a TR issue (hope it made it). -DWA .. Hmm, not sure I understand. Are you talking about whether a standards conforming input iterator is allowed to have a tag that is not input_iterator_tag but that is convertible to input_iterator_tag? -JGS The algorithms in the standard library benefit from the new iterator concepts because the new concepts provide a more accurate way to express their type requirements. The result is algorithms that are usable in more situations and have fewer type requirements. The following lists the proposed changes to the type requirements of algorithms. Forward Iterator -> Forward Traversal Iterator and Readable Iterator ``find_end, adjacent_find, search, search_n, rotate_copy, lower_bound, upper_bound, equal_range, binary_search, min_element, max_element`` Forward Iterator (1) -> Single Pass Iterator and Readable Iterator, Forward Iterator (2) -> Forward Traversal Iterator and Readable Iterator ``find_first_of`` Forward Iterator -> Readable Iterator and Writable Iterator ``iter_swap`` Forward Iterator -> Single Pass Iterator and Writable Iterator ``fill, generate`` Forward Iterator -> Forward Traversal Iterator and Swappable Iterator ``rotate`` Forward Iterator (1) -> Swappable Iterator and Single Pass Iterator, Forward Iterator (2) -> Swappable Iterator and Incrementable Iterator ``swap_ranges`` Forward Iterator -> Forward Traversal Iterator and Readable Iterator and Writable Iterator ``remove, remove_if, unique`` Forward Iterator -> Single Pass Iterator and Readable Iterator and Writable Iterator ``replace, replace_if`` Bidirectional Iterator -> Bidirectional Traversal Iterator and Swappable Iterator ``reverse`` Bidirectional Iterator -> Bidirectional Traversal Iterator and Readable and Swappable Iterator ``partition`` Bidirectional Iterator (1) -> Bidirectional Traversal Iterator and Readable Iterator, Bidirectional Iterator (2) -> Bidirectional Traversal Iterator and Writable Iterator ``copy_backwards`` Bidirectional Iterator -> Bidirectional Traversal Iterator and Swappable Iterator and Readable Iterator ``next_permutation, prev_permutation`` Bidirectional Iterator -> Bidirectional Traversal Iterator and Readable Iterator and Writable Iterator ``stable_partition, inplace_merge`` Bidirectional Iterator -> Bidirectional Traversal Iterator and Readable Iterator ``reverse_copy`` Random Access Iterator -> Random Access Traversal Iterator and Readable and Writable Iterator ``random_shuffle, sort, stable_sort, partial_sort, nth_element, push_heap, pop_heap make_heap, sort_heap`` Input Iterator (2) -> Incrementable Iterator and Readable Iterator ``equal, mismatch`` Input Iterator (2) -> Incrementable Iterator and Readable Iterator ``transform`` ======== Design ======== The iterator requirements are to be separated into two groups. One set of concepts handles the syntax and semantics of value access: - Readable Iterator - Writable Iterator - Swappable Iterator - Lvalue Iterator The access concepts describe requirements related to ``operator*`` and ``operator->``, including the ``value_type``, ``reference``, and ``pointer`` associated types. The other set of concepts handles traversal: - Incrementable Iterator - Single Pass Iterator - Forward Traversal Iterator - Bidirectional Traversal Iterator - Random Access Traversal Iterator The refinement relationships for the traversal concepts are in the following diagram. .. image:: traversal.png In addition to the iterator movement operators, such as ``operator++``, the traversal concepts also include requirements on position comparison such as ``operator==`` and ``operator<``. The reason for the fine grain slicing of the concepts into the Incrementable and Single Pass is to provide concepts that are exact matches with the original input and output iterator requirements. The relationship between the new iterator concepts and the old are given in the following diagram. .. image:: oldeqnew.png Like the old iterator requirements, we provide tags for purposes of dispatching based on the traversal concepts. The tags are related via inheritance so that a tag is convertible to another tag if the concept associated with the first tag is a refinement of the second tag. Since the access concepts are not related via refinment, but instead cover orthogonal issues, we do not use tags for the access concepts, but instead use the equivalent of a bitfield. We provide an access mechanism for mapping iterator types to the new traversal tags and access bitfield. Our design reuses ``iterator_traits::iterator_category`` as the access mechanism. To that end, the access and traversal information is bundled into a single type using the following `iterator_tag` class. :: enum iterator_access { readable_iterator = 1, writable_iterator = 2, swappable_iterator = 4, lvalue_iterator = 8 }; template struct iterator_tag : /* appropriate old category or categories */ { static const iterator_access access = x; typedef TraversalTag traversal; }; The ``iterator_tag`` class template is derived from the appropriate iterator tag or tags from the old requirements based on the new-style tags passed as template parameters. The algorithm for determining the old tag or tags from the new tags picks the least-refined old concepts that include all of the requirements of the access and traversal concepts (that is, the closest fit), if any such category exists. For example, a the category tag for a Readable Single Pass Iterator will always be derived from ``input_iterator_tag``, while the category tag for a Single Pass Iterator that is both Readable and Writable will be derived from both ``input_iterator_tag`` and ``output_iterator_tag``. We also provide several helper classes that make it convenient to obtain the access and traversal characteristics of an iterator. These helper classes work both for iterators whose ``iterator_category`` is ``iterator_tag`` and also for iterators using the original iterator categories. :: template struct is_readable { typedef ... type; }; template struct is_writable { typedef ... type; }; template struct is_swappable { typedef ... type; }; template struct traversal_category { typedef ... type; }; We do not include a helper class ``is_lvalue_iterator`` because that can easily be deduced by checking whether ``iterator_traits::reference`` is a real reference. The most difficult design decision concerned the ``operator[]``. The direct approach for specifying ``operator[]`` would have a return type of ``reference``; the same as ``operator*``. However, going in this direction would mean that an iterator satisfying the old Random Access Iterator requirements would not necessarily be a model of Readable or Writable Lvalue Iterator. Instead we have chosen a design that matches the preferred resolution of `issue 299`_: ``operator[]`` is only required to return something convertible to the ``value_type`` (for a Readable Iterator), and is required to support assignment ``i[n] = t`` (for a Writable Iterator). =============== Proposed Text =============== Addition to [lib.iterator.requirements] ======================================= Iterator Value Access Concepts [lib.iterator.value.access] ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ In the tables below, ``X`` is an iterator type, ``a`` is a constant object of type ``X``, ``T`` is ``std::iterator_traits::value_type``, and ``v`` is a constant object of type ``T``. .. _Readable Iterator: Readable Iterators [lib.readable.iterators] ------------------------------------------- A class or built-in type ``X`` models the *Readable Iterator* concept for the value type ``T`` if the following expressions are valid and respect the stated semantics. ``U`` is the type of any specified member of type ``T``. +-------------------------------------------------------------------------------------------------+ |Readable Iterator Requirements (in addition to CopyConstructible) | +-----------------------------------+-----------------------------------+-------------------------+ |Expression |Return Type |Note/Precondition | +===================================+===================================+=========================+ |``iterator_traits::value_type`` |``T`` |Any non-reference, | | | |non-cv-qualified type | +-----------------------------------+-----------------------------------+-------------------------+ |``iterator_traits::reference`` |Convertible to | | | |``iterator_traits::value_type`` | | +-----------------------------------+-----------------------------------+-------------------------+ |``is_readable::type`` |``true_type`` | | +-----------------------------------+-----------------------------------+-------------------------+ |``*a`` |``iterator_traits::reference`` |pre: ``a`` is | | | |dereferenceable. If ``a | | | |== b`` then ``*a`` is | | | |equivalent to ``*b`` | +-----------------------------------+-----------------------------------+-------------------------+ |``a->m`` |``U&`` |pre: ``(*a).m`` is | | | |well-defined. Equivalent| | | |to ``(*a).m`` | +-----------------------------------+-----------------------------------+-------------------------+ .. _Writable Iterator: Writable Iterators [lib.writable.iterators] ------------------------------------------- A class or built-in type ``X`` models the *Writable Iterator* concept if the following expressions are valid and respect the stated semantics. In addition, a model of *Writable Iterator* must include in its documentation the *set of value types* that it allows for output. +---------------------------------------------------------------------+ |Writable Iterator Requirements (in addition to CopyConstructible) | +-------------------------+--------------+----------------------------+ |Expression |Return Type |Precondition | +=========================+==============+============================+ |``is_writable::type`` |``true_type`` | | +-------------------------+--------------+----------------------------+ |``*a = o`` | | pre: The type of ``o`` | | | | is in the set of | | | | value types of ``X`` | +-------------------------+--------------+----------------------------+ Swappable Iterators [lib.swappable.iterators] --------------------------------------------- A class or built-in type ``X`` models the *Swappable Iterator* concept if the following expressions are valid and respect the stated semantics. +---------------------------------------------------------------------+ |Swappable Iterator Requirements (in addition to CopyConstructible) | +-------------------------+-------------+-----------------------------+ |Expression |Return Type |Postcondition | +=========================+=============+=============================+ |``is_swappable::type``|``true_type``| | +-------------------------+-------------+-----------------------------+ |``iter_swap(a, b)`` |``void`` |the pointed to values are | | | |exchanged | +-------------------------+-------------+-----------------------------+ [*Note:* An iterator that is a model of the *Readable* and *Writable Iterator* concepts is also a model of *Swappable Iterator*. *--end note*] Lvalue Iterators [lib.lvalue.iterators] --------------------------------------- The *Lvalue Iterator* concept adds the requirement that the ``reference`` type be a reference to the value type of the iterator. +---------------------------------------------------------------------------------+ | Lvalue Iterator Requirements | +---------------------------------+-----------+-----------------------------------+ |Expression |Return Type|Assertion | +=================================+===========+===================================+ |``iterator_traits::reference``|``T&`` |``T`` is *cv* | | | |``iterator_traits::value_type`` | | | |where *cv* is an optional | | | |cv-qualification | +---------------------------------+-----------+-----------------------------------+ Iterator Traversal Concepts [lib.iterator.traversal] ++++++++++++++++++++++++++++++++++++++++++++++++++++ In the tables below, ``X`` is an iterator type, ``a`` and ``b`` are constant objects of type ``X``, ``r`` and ``s`` are mutable objects of type ``X``, ``T`` is ``std::iterator_traits::value_type``, and ``v`` is a constant object of type ``T``. Incrementable Iterators [lib.incrementable.iterators] ----------------------------------------------------- A class or built-in type ``X`` models the *Incrementable Iterator* concept if the following expressions are valid and respect the stated semantics. +-------------------------------------------------------------------------------------+ |Incrementable Iterator Requirements (in addition to Assignable, Copy Constructible) | | | +--------------------------------+-------------------------------+--------------------+ |Expression |Return Type |Assertion/Semantics | +================================+===============================+====================+ |``++r`` |``X&`` |``&r == &++r`` | +--------------------------------+-------------------------------+--------------------+ |``r++`` |``X`` |:: | | | | | | | | { | | | | X tmp = r; | | | | ++r; | | | | return tmp; | | | | } | +--------------------------------+-------------------------------+--------------------+ |``traversal_category::type`` |Convertible to | | | |``incrementable_iterator_tag`` | | +--------------------------------+-------------------------------+--------------------+ Single Pass Iterators [lib.single.pass.iterators] ------------------------------------------------- A class or built-in type ``X`` models the *Single Pass Iterator* concept if the following expressions are valid and respect the stated semantics. +------------------------------------------------------------------------------------------+ |Single Pass Iterator Requirements (in addition to Incrementable Iterator and Equality | |Comparable) | +--------------------------------+-----------------------------+---------------------------+ |Expression |Return Type |Assertion/Semantics / | | | |Pre-/Post-condition | +================================+=============================+===========================+ |``++r`` |``X&`` |pre: ``r`` is | | | |dereferenceable; post: | | | |``r`` is dereferenceable or| | | |``r`` is past-the-end | +--------------------------------+-----------------------------+---------------------------+ |``a == b`` |convertible to ``bool`` |``==`` is an equivalence | | | |relation over its domain | +--------------------------------+-----------------------------+---------------------------+ |``a != b`` |convertible to ``bool`` |``!(a == b)`` | +--------------------------------+-----------------------------+---------------------------+ |``traversal_category::type`` |Convertible to | | | |``single_pass_iterator_tag`` | | +--------------------------------+-----------------------------+---------------------------+ Forward Traversal Iterators [lib.forward.traversal.iterators] ------------------------------------------------------------- A class or built-in type ``X`` models the *Forward Traversal Iterator* concept if the following expressions are valid and respect the stated semantics. +-------------------------------------------------------------------------------------------+ |Forward Traversal Iterator Requirements (in addition to Single Pass Iterator) | +---------------------------------------+-----------------------------------+---------------+ |Expression |Return Type |Assertion/Note | +=======================================+===================================+===============+ |``X u;`` |``X&`` |note: ``u`` may| | | |have a singular| | | |value. | +---------------------------------------+-----------------------------------+---------------+ |``++r`` |``X&`` |``r == s`` and | | | |``r`` is | | | |dereferenceable| | | |implies ``++r | | | |== ++s.`` | +---------------------------------------+-----------------------------------+---------------+ |``iterator_traits::difference_type``|A signed integral type representing| | | |the distance between iterators | | | | | | +---------------------------------------+-----------------------------------+---------------+ |``traversal_category::type`` |Convertible to | | | |``forward_traversal_iterator_tag`` | | +---------------------------------------+-----------------------------------+---------------+ Bidirectional Traversal Iterators [lib.bidirectional.traversal.iterators] ------------------------------------------------------------------------- A class or built-in type ``X`` models the *Bidirectional Traversal Iterator* concept if the following expressions are valid and respect the stated semantics. +--------------------------------------------------------------------------------------------------------+ |Bidirectional Traversal Iterator Requirements (in addition to Forward Traversal Iterator) | +------------------------------------+---------------------------------------------+---------------------+ |Expression |Return Type |Assertion/Semantics /| | | |Pre-/Post-condition | +====================================+=============================================+=====================+ |``--r`` |``X&`` |pre: there exists | | | |``s`` such that ``r | | | |== ++s``. post: | | | |``s`` is | | | |dereferenceable. | | | |``--(++r) == r``. | | | |``--r == --s`` | | | |implies ``r == | | | |s``. ``&r == &--r``. | +------------------------------------+---------------------------------------------+---------------------+ |``r--`` |convertible to ``const X&`` |:: | | | | | | | | { | | | | X tmp = r; | | | | --r; | | | | return tmp; | | | | } | +------------------------------------+---------------------------------------------+---------------------+ |``traversal_category::type`` |Convertible to | | | |``bidirectional_traversal_iterator_tag`` | | | | | | +------------------------------------+---------------------------------------------+---------------------+ Random Access Traversal Iterators [lib.random.access.traversal.iterators] ------------------------------------------------------------------------- A class or built-in type ``X`` models the *Random Access Traversal Iterator* concept if the following expressions are valid and respect the stated semantics. In the table below, ``Distance`` is ``iterator_traits::difference_type`` and ``n`` represents a constant object of type ``Distance``. +----------------------------------------------------------------------------------------------------------------------------------------------+ |Random Access Traversal Iterator Requirements (in addition to Bidirectional Traversal Iterator) | +-------------------------------------------+-------------------------------------------------+-------------------------+----------------------+ |Expression |Return Type |Operational Semantics |Assertion/ | | | | |Precondition | +===========================================+=================================================+=========================+======================+ |``r += n`` |``X&`` |:: | | | | | | | | | | { | | | | | Distance m = n; | | | | | if (m >= 0) | | | | | while (m--) | | | | | ++r; | | | | | else | | | | | while (m++) | | | | | --r; | | | | | return r; | | | | | } | | +-------------------------------------------+-------------------------------------------------+-------------------------+----------------------+ |``a + n``, ``n + a`` |``X`` |``{ X tmp = a; return tmp| | | | |+= n; }`` | | | | | | | +-------------------------------------------+-------------------------------------------------+-------------------------+----------------------+ |``r -= n`` |``X&`` |``return r += -n`` | | +-------------------------------------------+-------------------------------------------------+-------------------------+----------------------+ |``a - n`` |``X`` |``{ X tmp = a; return tmp| | | | |-= n; }`` | | | | | | | +-------------------------------------------+-------------------------------------------------+-------------------------+----------------------+ |``b - a`` |``Distance`` |``a < b ? distance(a,b) |pre: there exists a | | | |: -distance(b,a)`` |value ``n`` of | | | | |``Distance`` such that| | | | |``a + n == b``. ``b | | | | |== a + (b - a)``. | +-------------------------------------------+-------------------------------------------------+-------------------------+----------------------+ |``a[n]`` |convertible to T |``*(a + n)`` |pre: a is a `readable | | | | |iterator`_ | +-------------------------------------------+-------------------------------------------------+-------------------------+----------------------+ |``a[n] = v`` |convertible to T |``*(a + n) = v`` |pre: a is a `writable | | | | |iterator`_ | +-------------------------------------------+-------------------------------------------------+-------------------------+----------------------+ |``a < b`` |convertible to ``bool`` |``b - a > 0`` |``<`` is a total | | | | |ordering relation | +-------------------------------------------+-------------------------------------------------+-------------------------+----------------------+ |``a > b`` |convertible to ``bool`` |``b < a`` |``>`` is a total | | | | |ordering relation | +-------------------------------------------+-------------------------------------------------+-------------------------+----------------------+ |``a >= b`` |convertible to ``bool`` |``!(a < b)`` | | +-------------------------------------------+-------------------------------------------------+-------------------------+----------------------+ |``a <= b`` |convertible to ``bool`` |``!(a > b)`` | | +-------------------------------------------+-------------------------------------------------+-------------------------+----------------------+ |``traversal_category::type`` |Convertible to | | | | |``random_access_traversal_iterator_tag`` | | | +-------------------------------------------+-------------------------------------------------+-------------------------+----------------------+ Addition to [lib.iterator.synopsis] =================================== :: // lib.iterator.traits, traits and tags template struct is_readable; template struct is_writable; template struct is_swappable; template struct traversal_category; enum iterator_access { readable_iterator = 1, writable_iterator = 2, swappable_iterator = 4, lvalue_iterator = 8 }; template struct iterator_tag : /* appropriate old category or categories */ { static const iterator_access access = (iterator_access)access_bits; typedef TraversalTag traversal; }; struct incrementable_iterator_tag { }; struct single_pass_iterator_tag : incrementable_iterator_tag { }; struct forward_traversal_tag : single_pass_iterator_tag { }; struct bidirectional_traversal_tag : forward_traversal_tag { }; struct random_access_traversal_tag : bidirectional_traversal_tag { }; struct null_category_tag { }; struct input_output_iterator_tag : input_iterator_tag, output_iterator_tag {}; Addition to [lib.iterator.traits] ================================= The ``iterator_tag`` class template is an iterator category tag that encodes the access enum and traversal tag in addition to being compatible with the original iterator tags. The ``iterator_tag`` class inherits from one of the original iterator tags according to the following pseudo-code. :: inherit-category(access, traversal-tag) = if (access & lvalue_iterator) { if (traversal-tag is convertible to random_access_traversal_tag) return random_access_iterator_tag; else if (traversal-tag is convertible to bidirectional_traversal_tag) return bidirectional_iterator_tag; else if (traversal-tag is convertible to forward_traversal_tag) return forward_iterator_tag; else if (traversal-tag is convertible to single_pass_traversal_tag) if (access-tag is convertible to writable_iterator_tag) return input_output_iterator_tag; else return input_iterator_tag; else if (access & writable_iterator) return output_iterator_tag; else return null_category_tag; } else if ((access & readable_iterator) and (access & writable_iterator) and traversal-tag is convertible to single_pass_iterator_tag) return input_output_iterator_tag; else if (access & readable_iterator and traversal-tag is convertible to single_pass_iterator_tag) return input_iterator_tag; else if (access & writable_iterator and traversal-tag is convertible to incrementable_iterator_tag) return output_iterator_tag; else return null_category_tag; The access argument is declared to be ``unsigned int`` instead of the enum ``iterator_access`` for convenience of use. For example, the expression ``(readable_iterator | writable_iterator)`` produces an unsigned int, not ``iterator_access``. If the argument for ``TraversalTag`` is not convertible to ``incrementable_iterator_tag`` then the programm is ill-formed. The ``is_readable``, ``is_writable``, ``is_swappable``, and ``traversal_category`` class templates are traits classes. For iterators whose ``iterator_traits::iterator_category`` type is ``iterator_tag``, these traits obtain the ``access`` enum and ``traversal`` member type from within ``iterator_tag``. For iterators whose ``iterator_traits::iterator_category`` type is not ``iterator_tag`` and instead is a tag convertible to one of the original tags, the appropriate traversal tag and access bits are deduced. The following pseudo-code describes the algorithm. :: is-readable(Iterator) = cat = iterator_traits::iterator_category; if (cat == iterator_tag) return Access % readable_iterator; else if (cat is convertible to input_iterator_tag) return true; else return false; is-writable(Iterator) = cat = iterator_traits::iterator_category; if (cat == iterator_tag) return Access % writable_iterator; else if (cat is convertible to forward_iterator_tag or output_iterator_tag) return true; else return false; is-swappable(Iterator) = cat = iterator_traits::iterator_category; if (cat == iterator_tag) return Access % swappable_iterator; else if (cat is convertible to forward_iterator_tag) { if (iterator_traits::reference is a const reference) return false; else return true; } else return false; traversal-category(Iterator) = cat = iterator_traits::iterator_category; if (cat == iterator_tag) return Traversal; else if (cat is convertible to random_access_iterator_tag) return random_access_traversal_tag; else if (cat is convertible to bidirectional_iterator_tag) return bidirectional_traversal_tag; else if (cat is convertible to forward_iterator_tag) return forward_traversal_tag; else if (cat is convertible to input_iterator_tag) return single_pass_iterator_tag; else if (cat is convertible to output_iterator_tag) return incrementable_iterator_tag; else return null_category_tag; The following specializations provide the access and traversal category tags for pointer types. :: template struct is_readable { typedef true_type type; }; template struct is_writable { typedef false_type type; }; template struct is_swappable { typedef false_type type; }; template struct is_readable { typedef true_type type; }; template struct is_writable { typedef true_type type; }; template struct is_swappable { typedef true_type type; }; template struct traversal_category { typedef random_access_traversal_tag type; }; .. LocalWords: Abrahams Siek Witt const bool Sutter's WG int UL LI href Lvalue LocalWords: ReadableIterator WritableIterator SwappableIterator cv pre iter LocalWords: ConstantLvalueIterator MutableLvalueIterator CopyConstructible TR LocalWords: ForwardTraversalIterator BidirectionalTraversalIterator lvalue LocalWords: RandomAccessTraversalIterator dereferenceable Incrementable tmp LocalWords: incrementable xxx min prev inplace png oldeqnew AccessTag struct LocalWords: TraversalTag typename lvalues DWA Hmm JGS