mirror of
https://github.com/boostorg/iterator.git
synced 2025-05-12 14:01:37 +00:00
3842 lines
140 KiB
ReStructuredText
3842 lines
140 KiB
ReStructuredText
+++++++++++++++++++++++++++++++++++++
|
|
Iterator concept and adapter issues
|
|
+++++++++++++++++++++++++++++++++++++
|
|
|
|
:date: $Date$
|
|
|
|
.. contents:: Index
|
|
|
|
===================================
|
|
Issues from Matt's TR issues list
|
|
===================================
|
|
|
|
|
|
9.1 iterator_access overspecified?
|
|
==================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
The proposal includes::
|
|
|
|
enum iterator_access {
|
|
readable_iterator = 1, writable_iterator = 2,
|
|
swappable_iterator = 4, lvalue_iterator = 8
|
|
};
|
|
|
|
In general, the standard specifies thing like this as a bitmask
|
|
type with a list of defined names, and specifies neither the exact
|
|
type nor the specific values. Is there a reason for iterator_access
|
|
to be more specific?
|
|
|
|
:Proposed resolution: The ``iterator_access`` enum will be removed,
|
|
so this is no longer an issue. See the resolution to 9.15.
|
|
|
|
|
|
9.2 operators of iterator_facade overspecified
|
|
==============================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
In general, we've provided operational semantics for things like
|
|
operator++. That is, we've said that ++iter must work, without
|
|
requiring either a member function or a non-member function.
|
|
iterator_facade specifies most operators as member
|
|
functions. There's no inherent reason for these to be members, so
|
|
we should remove this requirement. Similarly, some operations are
|
|
specified as non-member functions but could be implemented as
|
|
members. Again, the standard doesn't make either of these choices,
|
|
and TR1 shouldn't, either. So: ``operator*()``, ``operator++()``,
|
|
``operator++(int)``, ``operator--()``, ``operator--(int)``,
|
|
``operator+=``, ``operator-=``, ``operator-(difference_type)``,
|
|
``operator-(iterator_facade instance)``, and ``operator+`` should
|
|
be specified with operational semantics and not explicitly required
|
|
to be members or non-members.
|
|
|
|
:Proposed resolution: Not a defect.
|
|
|
|
:Rationale: The standard uses valid expressions such as ``++iter``
|
|
in requirements tables, such as for input iterator. However, for
|
|
classes, such as ``reverse_iterator``, the standard uses function
|
|
prototypes, as we have done here for
|
|
``iterator_facade``. Further, the prototype specification does
|
|
not prevent the implementor from using members or non-members,
|
|
since nothing the user can do in a conforming program can detect
|
|
how the function is implemented.
|
|
|
|
|
|
9.3 enable_if_interoperable needs standardese
|
|
=============================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
The only discussion of what this means is in a note, so is
|
|
non-normative. Further, the note seems to be incorrect. It says
|
|
that enable_if_interoperable only works for types that "are
|
|
interoperable, by which we mean they are convertible to each
|
|
other." This requirement is too strong: it should be that one of
|
|
the types is convertible to the other. N1541 48
|
|
|
|
:Proposed resolution: Add normative text. Relax requirements in the
|
|
proposed way.
|
|
|
|
Change:
|
|
|
|
[*Note:* The ``enable_if_interoperable`` template used above is
|
|
for exposition purposes. The member operators should be only be
|
|
in an overload set provided the derived types ``Dr1`` and
|
|
``Dr2`` are interoperable, by which we mean they are
|
|
convertible to each other. The ``enable_if_interoperable``
|
|
approach uses SFINAE to take the operators out of the overload
|
|
set when the types are not interoperable.]
|
|
|
|
To:
|
|
|
|
The ``enable_if_interoperable`` template used above is for
|
|
exposition purposes. The member operators should only be in an
|
|
overload set provided the derived types ``Dr1`` and ``Dr2`` are
|
|
interoperable, meaning that at least one of the types is
|
|
convertible to the other. The ``enable_if_interoperable``
|
|
approach uses SFINAE to take the operators out of the overload
|
|
set when the types are not interoperable. The operators should
|
|
behave *as-if* ``enable_if_interoperable`` were defined to be::
|
|
|
|
template <bool, typename> enable_if_interoperable_impl
|
|
{};
|
|
|
|
template <typename T> enable_if_interoperable_impl<true,T>
|
|
{ typedef T type; };
|
|
|
|
template<typename Dr1, typename Dr2, typename T>
|
|
struct enable_if_interoperable
|
|
: enable_if_interoperable_impl<
|
|
is_convertible<Dr1,Dr2>::value || is_convertible<Dr2,Dr1>::value
|
|
, T
|
|
>
|
|
{};
|
|
|
|
9.4 enable_if_convertible unspecified, conflicts with requires
|
|
==============================================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
In every place where enable_if_convertible is used it's used like
|
|
this (simplified)::
|
|
|
|
template<class T>
|
|
struct C
|
|
{
|
|
template<class T1>
|
|
C(T1, enable_if_convertible<T1, T>::type* = 0);
|
|
};
|
|
|
|
The idea being that this constructor won't compile if T1 isn't
|
|
convertible to T. As a result, the constructor won't be considered
|
|
as a possible overload when constructing from an object x where the
|
|
type of x isn't convertible to T. In addition, however, each of
|
|
these constructors has a requires clause that requires
|
|
convertibility, so the behavior of a program that attempts such a
|
|
construction is undefined. Seems like the enable_if_convertible
|
|
part is irrelevant, and should be removed. There are two
|
|
problems. First, enable_if_convertible is never specified, so we
|
|
don't know what this is supposed to do. Second: we could reasonably
|
|
say that this overload should be disabled in certain cases or we
|
|
could reasonably say that behavior is undefined, but we can't say
|
|
both.
|
|
|
|
Thomas Witt writes that the goal of putting in
|
|
enable_if_convertible here is to make sure that a specific overload
|
|
doesn't interfere with the generic case except when that overload
|
|
makes sense. He agrees that what we currently have is deficient.
|
|
Dave Abrahams writes that there is no conflict with the requires
|
|
cause because the requires clause only takes effect when the
|
|
function is actually called. The presence of the constructor
|
|
signature can/will be detected by is_convertible without violating
|
|
the requires clause, and thus it makes a difference to disable
|
|
those constructor instantiations that would be disabled by
|
|
enable_if_convertible even if calling them invokes undefined
|
|
behavior. There was more discussion on the reflector:
|
|
c++std-lib-12312, c++std-lib-12325, c++std-lib- 12330,
|
|
c++std-lib-12334, c++std-lib-12335, c++std-lib-12336,
|
|
c++std-lib-12338, c++std-lib- 12362.
|
|
|
|
:Proposed resolution:
|
|
Change:
|
|
|
|
[*Note:* The ``enable_if_convertible<X,Y>::type`` expression
|
|
used in this section is for exposition purposes. The converting
|
|
constructors for specialized adaptors should be only be in an
|
|
overload set provided that an object of type ``X`` is
|
|
implicitly convertible to an object of type ``Y``. The
|
|
``enable_if_convertible`` approach uses SFINAE to take the
|
|
constructor out of the overload set when the types are not
|
|
implicitly convertible.]
|
|
|
|
To:
|
|
|
|
The ``enable_if_convertible<X,Y>::type`` expression used in
|
|
this section is for exposition purposes. The converting
|
|
constructors for specialized adaptors should be only be in an
|
|
overload set provided that an object of type ``X`` is
|
|
implicitly convertible to an object of type ``Y``. The
|
|
signatures involving ``enable_if_convertible`` should behave
|
|
*as-if* ``enable_if_convertible`` were defined to be::
|
|
|
|
template <bool> enable_if_convertible_impl
|
|
{};
|
|
|
|
template <> enable_if_convertible_impl<true>
|
|
{ struct type; };
|
|
|
|
template<typename From, typename To>
|
|
struct enable_if_convertible
|
|
: enable_if_convertible_impl<is_convertible<From,To>::value>
|
|
{};
|
|
|
|
If an expression other than the default argument is used to
|
|
supply the value of a function parameter whose type is written
|
|
in terms of ``enable_if_convertible``, the program is
|
|
ill-formed, no diagnostic required.
|
|
|
|
[*Note:* The ``enable_if_convertible`` approach uses SFINAE to
|
|
take the constructor out of the overload set when the types are
|
|
not implicitly convertible. ]
|
|
|
|
9.5 iterator_adaptor has an extraneous 'bool' at the start of the template definition
|
|
=====================================================================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
The title says it all; this is probably just a typo.
|
|
|
|
:Proposed resolution: Remove the 'bool'.
|
|
|
|
9.6 Name of private member shouldn't be normative
|
|
=================================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
iterator_adaptor has a private member named m_iterator. Presumably
|
|
this is for exposition only, since it's an implementation
|
|
detail. It needs to be marked as such.
|
|
|
|
:Proposed resolution: Mark the member ``m_iterator`` as exposition
|
|
only. Note/DWA: I think this is NAD because the user can't
|
|
detect it, though I'm happy to mark it exposition only.
|
|
|
|
In [lib.iterator.adaptor]
|
|
|
|
Change::
|
|
|
|
Base m_iterator;
|
|
|
|
to::
|
|
|
|
Base m_iterator; // exposition only
|
|
|
|
|
|
9.7 iterator_adaptor operations specifications are a bit inconsistent
|
|
=====================================================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
iterator_adpator() has a Requires clause, that Base must be default
|
|
constructible. iterator_adaptor(Base) has no Requires clause,
|
|
although the Returns clause says that the Base member is copy
|
|
construced from the argument (this may actually be an oversight in
|
|
N1550, which doesn't require iterators to be copy constructible or
|
|
assignable).
|
|
|
|
:Proposed resolution: Add a requirements section for the template
|
|
parameters of iterator_adaptor, and state that Base must be Copy
|
|
Constructible and Assignable.
|
|
|
|
N1550 does in fact include requirements for copy constructible
|
|
and assignable in the requirements tables. To clarify, we've also
|
|
added the requirements to the text.
|
|
|
|
|
|
9.8 Specialized adaptors text should be normative
|
|
=================================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
similar to 9.3, "Specialized Adaptors" has a note describing
|
|
enable_if_convertible. This should be normative text.
|
|
|
|
:Proposed resolution: Changed it to normative
|
|
text. See the resolution of 9.4
|
|
|
|
9.9 Reverse_iterator text is too informal
|
|
=========================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
reverse iterator "flips the direction of the base iterator's
|
|
motion". This needs to be more formal, as in the current
|
|
standard. Something like: "iterates through the controlled sequence
|
|
in the opposite direction"
|
|
|
|
:Proposed resolution:
|
|
|
|
Change:
|
|
|
|
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.
|
|
|
|
to:
|
|
|
|
The reverse iterator adaptor iterates through the adapted iterator
|
|
range in the opposite direction.
|
|
|
|
|
|
9.10 'prior' is undefined
|
|
=========================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
reverse_iterator::dereference is specified as calling a function
|
|
named 'prior' which has no specification.
|
|
|
|
:Proposed resolution:
|
|
Change the specification to avoid using ``prior`` as follows.
|
|
|
|
Remove::
|
|
|
|
typename reverse_iterator::reference dereference() const { return *prior(this->base()); }
|
|
|
|
And at the end of the operations section add:
|
|
|
|
``reference operator*() const;``
|
|
|
|
:Effects:
|
|
|
|
::
|
|
|
|
Iterator tmp = m_iterator;
|
|
return *--tmp;
|
|
|
|
:Rationale:
|
|
The style of specification has changed because of issue 9.37x.
|
|
|
|
|
|
|
|
9.11 "In other words" is bad wording
|
|
====================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
Transform iterator has a two-part specification: it does this, in
|
|
other words, it does that. "In other words" always means "I didn't
|
|
say it right, so I'll try again." We need to say it once.
|
|
|
|
:Proposed resolution:
|
|
Change:
|
|
|
|
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.
|
|
|
|
to:
|
|
|
|
The transform iterator adapts an iterator by modifying the
|
|
``operator*`` to apply a function object to the result of
|
|
dereferencing the iterator and returning the result.
|
|
|
|
|
|
9.12 Transform_iterator shouldn't mandate private member
|
|
========================================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
transform_iterator has a private member named 'm_f' which should be
|
|
marked "exposition only."
|
|
|
|
:Proposed resolution: Mark the member ``m_f`` as exposition
|
|
only. Note/DWA: I think this is NAD because the user can't
|
|
detect it, though I'm happy to mark it exposition only.
|
|
|
|
Change::
|
|
|
|
UnaryFunction m_f;
|
|
|
|
to::
|
|
|
|
UnaryFunction m_f; // exposition only
|
|
|
|
|
|
|
|
9.13 Unclear description of counting iterator
|
|
=============================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
The description of Counting iterator is unclear. "The counting
|
|
iterator adaptor implements dereference by returning a reference to
|
|
the base object. The other operations are implemented by the base
|
|
m_iterator, as per the inheritance from iterator_adaptor."
|
|
|
|
:Proposed resolution:
|
|
Change:
|
|
|
|
The counting iterator adaptor implements dereference by
|
|
returning a reference to the base object. The other operations
|
|
are implemented by the base ``m_iterator``, as per the
|
|
inheritance from ``iterator_adaptor``.
|
|
|
|
to:
|
|
|
|
``counting_iterator`` adapts an object by adding an
|
|
``operator*`` that returns the current value of the object. All
|
|
other iterator operations are forwarded to the adapted object.
|
|
|
|
|
|
|
|
9.14 Counting_iterator's difference type
|
|
========================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
Counting iterator has the following note:
|
|
|
|
[Note: implementers are encouraged to provide an implementation
|
|
of distance_to and a difference_type that avoids overflows in the
|
|
cases when the Incrementable type is a numeric type.]
|
|
|
|
I'm not sure what this means. The user provides a template argument
|
|
named Difference, but there's no difference_type. I assume this is
|
|
just a glitch in the wording. But if implementors are encouraged to
|
|
ignore this argument if it won't work right, why is it there?
|
|
|
|
:Proposed resolution: The ``difference_type`` was inherited from
|
|
``iterator_adaptor``. However, we've removed the explicit
|
|
inheritance, so explicit typedefs have been added. See the
|
|
resolution of 9.37x.
|
|
|
|
|
|
|
|
9.15 How to detect lvalueness?
|
|
==============================
|
|
|
|
:Submitter: Dave Abrahams
|
|
:Status: New
|
|
|
|
Shortly after N1550 was accepted, we discovered that an iterator's
|
|
lvalueness can be determined knowing only its value_type. This
|
|
predicate can be calculated even for old-style iterators (on whose
|
|
reference type the standard places few requirements). A trait in
|
|
the Boost iterator library does it by relying on the compiler's
|
|
unwillingness to bind an rvalue to a T& function template
|
|
parameter. Similarly, it is possible to detect an iterator's
|
|
readability knowing only its value_type. Thus, any interface which
|
|
asks the user to explicitly describe an iterator's lvalue-ness or
|
|
readability seems to introduce needless complexity.
|
|
|
|
|
|
:Proposed resolution:
|
|
|
|
1. Remove the ``is_writable`` and ``is_swappable`` traits, and
|
|
remove the requirements in the Writable Iterator and Swappable
|
|
Iterator concepts that require their models to support these
|
|
traits.
|
|
|
|
2. Change the ``is_readable`` specification. Remove the
|
|
requirement for support of the ``is_readable`` trait from the
|
|
Readable Iterator concept.
|
|
|
|
3. Remove the ``iterator_tag`` class and transplant the logic for
|
|
choosing an iterator category into ``iterator_facade``.
|
|
|
|
4. Change the specification of ``traversal_category``.
|
|
|
|
5. Remove Access parameters from N1530
|
|
|
|
In N1550:
|
|
|
|
Remove:
|
|
|
|
Since the access concepts are not related via refinement, but
|
|
instead cover orthogonal issues, we do not use tags for the
|
|
access concepts, but instead use the equivalent of a bit field.
|
|
|
|
We provide an access mechanism for mapping iterator types to
|
|
the new traversal tags and access bit field. Our design reuses
|
|
``iterator_traits<Iter>::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 <unsigned int access_bits, class TraversalTag>
|
|
struct iterator_tag : /* appropriate old category or categories */ {
|
|
static const iterator_access access =
|
|
(iterator_access)access_bits &
|
|
(readable_iterator | writable_iterator | swappable_iterator);
|
|
typedef TraversalTag traversal;
|
|
};
|
|
|
|
The ``access_bits`` 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 an
|
|
``iterator_access``. The purpose of the ``lvalue_iterator``
|
|
part of the ``iterator_access`` enum is to communicate to
|
|
``iterator_tag`` whether the reference type is an lvalue so
|
|
that the appropriate old category can be chosen for the base
|
|
class. The ``lvalue_iterator`` bit is not recorded in the
|
|
``iterator_tag::access`` data member.
|
|
|
|
The ``iterator_tag`` class template is derived from the
|
|
appropriate iterator tag or tags from the old requirements
|
|
based on the access bits and traversal tag passed as template
|
|
parameters. The algorithm for determining the old tag or 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, 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 <class Iterator> struct is_readable { typedef ... type; };
|
|
template <class Iterator> struct is_writable { typedef ... type; };
|
|
template <class Iterator> struct is_swappable { typedef ... type; };
|
|
template <class Iterator> struct traversal_category { typedef ... type; };
|
|
|
|
|
|
After:
|
|
|
|
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.
|
|
|
|
Add:
|
|
|
|
Our design reuses ``iterator_traits<Iter>::iterator_category``
|
|
to indicate an iterator's traversal capability. To specify
|
|
capabilities not captured by any old-style iterator category,
|
|
an iterator designer can use an ``iterator_category`` type that
|
|
is convertible to both the the most-derived old iterator
|
|
category tag which fits, and the appropriate new iterator
|
|
traversal tag.
|
|
|
|
We do not provide tags for the purposes of dispatching based on
|
|
the access concepts, in part because we could not find a way to
|
|
automatically infer the right access tags for old-style
|
|
iterators. An iterator's writability may be dependent on the
|
|
assignability of its ``value_type`` and there's no known way to
|
|
detect whether an arbitrary type is assignable. Fortunately,
|
|
the need for dispatching based on access capability is not as
|
|
great as the need for dispatching based on traversal
|
|
capability.
|
|
|
|
|
|
From the Readable Iterator Requirements table, remove:
|
|
|
|
+-----------------------------------+-----------------------------------+-------------------------+
|
|
|``is_readable<X>::type`` |``true_type`` | |
|
|
+-----------------------------------+-----------------------------------+-------------------------+
|
|
|
|
From the Writable Iterator Requirements table, remove:
|
|
|
|
+-------------------------+--------------+----------------------------+
|
|
|``is_writable<X>::type`` |``true_type`` | |
|
|
+-------------------------+--------------+----------------------------+
|
|
|
|
From the Swappable Iterator Requirements table, remove:
|
|
|
|
+-------------------------+-------------+-----------------------------+
|
|
|``is_swappable<X>::type``|``true_type``| |
|
|
+-------------------------+-------------+-----------------------------+
|
|
|
|
|
|
From [lib.iterator.synopsis] replace::
|
|
|
|
template <class Iterator> struct is_readable;
|
|
template <class Iterator> struct is_writable;
|
|
template <class Iterator> struct is_swappable;
|
|
template <class Iterator> struct traversal_category;
|
|
|
|
enum iterator_access { readable_iterator = 1, writable_iterator = 2,
|
|
swappable_iterator = 4, lvalue_iterator = 8 };
|
|
|
|
template <unsigned int access_bits, class TraversalTag>
|
|
struct iterator_tag : /* appropriate old category or categories */ {
|
|
static const iterator_access access =
|
|
(iterator_access)access_bits &
|
|
(readable_iterator | writable_iterator | swappable_iterator);
|
|
typedef TraversalTag traversal;
|
|
};
|
|
|
|
with::
|
|
|
|
template <class Iterator> struct is_readable_iterator;
|
|
template <class Iterator> struct iterator_traversal;
|
|
|
|
|
|
In [lib.iterator.traits], remove:
|
|
|
|
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 & readable_iterator) && (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
|
|
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;
|
|
|
|
If the argument for ``TraversalTag`` is not convertible to
|
|
``incrementable_iterator_tag`` then the program is ill-formed.
|
|
|
|
Change:
|
|
|
|
The ``is_readable``, ``is_writable``, ``is_swappable``, and
|
|
``traversal_category`` class templates are traits classes. For
|
|
iterators whose ``iterator_traits<Iter>::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<Iter>::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>::iterator_category;
|
|
if (cat == iterator_tag<Access,Traversal>)
|
|
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>::iterator_category;
|
|
if (cat == iterator_tag<Access,Traversal>)
|
|
return Access & writable_iterator;
|
|
else if (cat is convertible to output_iterator_tag)
|
|
return true;
|
|
else if (
|
|
cat is convertible to forward_iterator_tag
|
|
and iterator_traits<Iterator>::reference is a
|
|
mutable reference)
|
|
return true;
|
|
else
|
|
return false;
|
|
|
|
is-swappable(Iterator) =
|
|
cat = iterator_traits<Iterator>::iterator_category;
|
|
if (cat == iterator_tag<Access,Traversal>)
|
|
return Access & swappable_iterator;
|
|
else if (cat is convertible to forward_iterator_tag) {
|
|
if (iterator_traits<Iterator>::reference is a const reference)
|
|
return false;
|
|
else
|
|
return true;
|
|
} else
|
|
return false;
|
|
|
|
traversal-category(Iterator) =
|
|
cat = iterator_traits<Iterator>::iterator_category;
|
|
if (cat == iterator_tag<Access,Traversal>)
|
|
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 <typename T>
|
|
struct is_readable<const T*> { typedef true_type type; };
|
|
template <typename T>
|
|
struct is_writable<const T*> { typedef false_type type; };
|
|
template <typename T>
|
|
struct is_swappable<const T*> { typedef false_type type; };
|
|
|
|
template <typename T>
|
|
struct is_readable<T*> { typedef true_type type; };
|
|
template <typename T>
|
|
struct is_writable<T*> { typedef true_type type; };
|
|
template <typename T>
|
|
struct is_swappable<T*> { typedef true_type type; };
|
|
|
|
template <typename T>
|
|
struct traversal_category<T*>
|
|
{
|
|
typedef random_access_traversal_tag type;
|
|
};
|
|
|
|
to:
|
|
|
|
The ``is_readable_iterator`` class template satisfies the
|
|
UnaryTypeTrait requirements.
|
|
|
|
Given an iterator type ``X``,
|
|
``is_readable_iterator<X>::value`` yields ``true`` if, for an
|
|
object ``a`` of type ``X``, ``*a`` is convertible to
|
|
``iterator_traits<X>::value_type``, and ``false`` otherwise.
|
|
|
|
.. _`category-to-traversal`:
|
|
|
|
``iterator_traversal<X>::type`` is
|
|
|
|
.. parsed-literal::
|
|
|
|
*category-to-traversal*\ (iterator_traits<X>::iterator_category)
|
|
|
|
where *category-to-traversal* is defined as follows
|
|
|
|
.. parsed-literal::
|
|
|
|
*category-to-traversal*\ (C) =
|
|
if (C is convertible to incrementable_traversal_tag)
|
|
return C;
|
|
else if (C is convertible to random_access_iterator_tag)
|
|
return random_access_traversal_tag;
|
|
else if (C is convertible to bidirectional_iterator_tag)
|
|
return bidirectional_traversal_tag;
|
|
else if (C is convertible to forward_iterator_tag)
|
|
return forward_traversal_tag;
|
|
else if (C is convertible to input_iterator_tag)
|
|
return single_pass_traversal_tag;
|
|
else if (C is convertible to output_iterator_tag)
|
|
return incrementable_traversal_tag;
|
|
else
|
|
*the program is ill-formed*
|
|
|
|
In N1530:
|
|
|
|
In [lib.iterator.helper.synopsis]:
|
|
|
|
Change::
|
|
|
|
const unsigned use_default_access = -1;
|
|
|
|
struct iterator_core_access { /* implementation detail */ };
|
|
|
|
template <
|
|
class Derived
|
|
, class Value
|
|
, unsigned AccessCategory
|
|
, class TraversalCategory
|
|
, class Reference = Value&
|
|
, class Difference = ptrdiff_t
|
|
>
|
|
class iterator_facade;
|
|
|
|
template <
|
|
class Derived
|
|
, class Base
|
|
, class Value = use_default
|
|
, unsigned Access = use_default_access
|
|
, class Traversal = use_default
|
|
, class Reference = use_default
|
|
, class Difference = use_default
|
|
>
|
|
class iterator_adaptor;
|
|
|
|
template <
|
|
class Iterator
|
|
, class Value = use_default
|
|
, unsigned Access = use_default_access
|
|
, class Traversal = use_default
|
|
, class Reference = use_default
|
|
, class Difference = use_default
|
|
>
|
|
class indirect_iterator;
|
|
|
|
To::
|
|
|
|
struct iterator_core_access { /* implementation detail */ };
|
|
|
|
template <
|
|
class Derived
|
|
, class Value
|
|
, class CategoryOrTraversal
|
|
, class Reference = Value&
|
|
, class Difference = ptrdiff_t
|
|
>
|
|
class iterator_facade;
|
|
|
|
template <
|
|
class Derived
|
|
, class Base
|
|
, class Value = use_default
|
|
, class CategoryOrTraversal = use_default
|
|
, class Reference = use_default
|
|
, class Difference = use_default
|
|
>
|
|
class iterator_adaptor;
|
|
|
|
template <
|
|
class Iterator
|
|
, class Value = use_default
|
|
, class CategoryOrTraversal = use_default
|
|
, class Reference = use_default
|
|
, class Difference = use_default
|
|
>
|
|
class indirect_iterator;
|
|
|
|
Change::
|
|
|
|
template <
|
|
class Incrementable
|
|
, unsigned Access = use_default_access
|
|
, class Traversal = use_default
|
|
, class Difference = use_default
|
|
>
|
|
class counting_iterator
|
|
|
|
To::
|
|
|
|
template <
|
|
class Incrementable
|
|
, class CategoryOrTraversal = use_default
|
|
, class Difference = use_default
|
|
>
|
|
class counting_iterator;
|
|
|
|
In [lib.iterator.facade]:
|
|
|
|
Change::
|
|
|
|
template <
|
|
class Derived
|
|
, class Value
|
|
, unsigned AccessCategory
|
|
, class TraversalCategory
|
|
, class Reference = /* see below */
|
|
, class Difference = ptrdiff_t
|
|
>
|
|
class iterator_facade {
|
|
|
|
to::
|
|
|
|
template <
|
|
class Derived
|
|
, class Value
|
|
, class CategoryOrTraversal
|
|
, class Reference = Value&
|
|
, class Difference = ptrdiff_t
|
|
>
|
|
class iterator_facade {
|
|
|
|
|
|
Change::
|
|
|
|
typedef iterator_tag<AccessCategory, TraversalCategory> iterator_category;
|
|
|
|
to::
|
|
|
|
typedef /* see below */ iterator_category;
|
|
|
|
|
|
Change::
|
|
|
|
// Comparison operators
|
|
template <class Dr1, class V1, class AC1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class AC2, class TC2, class R2, class D2>
|
|
typename enable_if_interoperable<Dr1, Dr2, bool>::type // exposition
|
|
operator ==(iterator_facade<Dr1, V1, AC1, TC1, R1, D1> const& lhs,
|
|
iterator_facade<Dr2, V2, AC2, TC2, R2, D2> const& rhs);
|
|
|
|
template <class Dr1, class V1, class AC1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class AC2, class TC2, class R2, class D2>
|
|
typename enable_if_interoperable<Dr1, Dr2, bool>::type
|
|
operator !=(iterator_facade<Dr1, V1, AC1, TC1, R1, D1> const& lhs,
|
|
iterator_facade<Dr2, V2, AC2, TC2, R2, D2> const& rhs);
|
|
|
|
template <class Dr1, class V1, class AC1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class AC2, class TC2, class R2, class D2>
|
|
typename enable_if_interoperable<Dr1, Dr2, bool>::type
|
|
operator <(iterator_facade<Dr1, V1, AC1, TC1, R1, D1> const& lhs,
|
|
iterator_facade<Dr2, V2, AC2, TC2, R2, D2> const& rhs);
|
|
|
|
template <class Dr1, class V1, class AC1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class AC2, class TC2, class R2, class D2>
|
|
typename enable_if_interoperable<Dr1, Dr2, bool>::type
|
|
operator <=(iterator_facade<Dr1, V1, AC1, TC1, R1, D1> const& lhs,
|
|
iterator_facade<Dr2, V2, AC2, TC2, R2, D2> const& rhs);
|
|
|
|
template <class Dr1, class V1, class AC1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class AC2, class TC2, class R2, class D2>
|
|
typename enable_if_interoperable<Dr1, Dr2, bool>::type
|
|
operator >(iterator_facade<Dr1, V1, AC1, TC1, R1, D1> const& lhs,
|
|
iterator_facade<Dr2, V2, AC2, TC2, R2, D2> const& rhs);
|
|
|
|
template <class Dr1, class V1, class AC1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class AC2, class TC2, class R2, class D2>
|
|
typename enable_if_interoperable<Dr1, Dr2, bool>::type
|
|
operator >=(iterator_facade<Dr1, V1, AC1, TC1, R1, D1> const& lhs,
|
|
iterator_facade<Dr2, V2, AC2, TC2, R2, D2> const& rhs);
|
|
|
|
template <class Dr1, class V1, class AC1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class AC2, class TC2, class R2, class D2>
|
|
typename enable_if_interoperable<Dr1, Dr2, bool>::type
|
|
operator >=(iterator_facade<Dr1, V1, AC1, TC1, R1, D1> const& lhs,
|
|
iterator_facade<Dr2, V2, AC2, TC2, R2, D2> const& rhs);
|
|
|
|
// Iterator difference
|
|
template <class Dr1, class V1, class AC1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class AC2, class TC2, class R2, class D2>
|
|
typename enable_if_interoperable<Dr1, Dr2, bool>::type
|
|
operator -(iterator_facade<Dr1, V1, AC1, TC1, R1, D1> const& lhs,
|
|
iterator_facade<Dr2, V2, AC2, TC2, R2, D2> const& rhs);
|
|
|
|
// Iterator addition
|
|
template <class Derived, class V, class AC, class TC, class R, class D>
|
|
Derived operator+ (iterator_facade<Derived, V, AC, TC, R, D> const&,
|
|
typename Derived::difference_type n)
|
|
|
|
to::
|
|
|
|
// Comparison operators
|
|
template <class Dr1, class V1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class TC2, class R2, class D2>
|
|
typename enable_if_interoperable<Dr1,Dr2,bool>::type // exposition
|
|
operator ==(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
|
|
iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
|
|
|
|
template <class Dr1, class V1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class TC2, class R2, class D2>
|
|
typename enable_if_interoperable<Dr1,Dr2,bool>::type
|
|
operator !=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
|
|
iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
|
|
|
|
template <class Dr1, class V1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class TC2, class R2, class D2>
|
|
typename enable_if_interoperable<Dr1,Dr2,bool>::type
|
|
operator <(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
|
|
iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
|
|
|
|
template <class Dr1, class V1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class TC2, class R2, class D2>
|
|
typename enable_if_interoperable<Dr1,Dr2,bool>::type
|
|
operator <=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
|
|
iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
|
|
|
|
template <class Dr1, class V1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class TC2, class R2, class D2>
|
|
typename enable_if_interoperable<Dr1,Dr2,bool>::type
|
|
operator >(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
|
|
iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
|
|
|
|
template <class Dr1, class V1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class TC2, class R2, class D2>
|
|
typename enable_if_interoperable<Dr1,Dr2,bool>::type
|
|
operator >=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
|
|
iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
|
|
|
|
// Iterator difference
|
|
template <class Dr1, class V1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class TC2, class R2, class D2>
|
|
/* see below */
|
|
operator-(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
|
|
iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
|
|
|
|
// Iterator addition
|
|
template <class Dr, class V, class TC, class R, class D>
|
|
Derived operator+ (iterator_facade<Dr,V,TC,R,D> const&,
|
|
typename Derived::difference_type n);
|
|
|
|
template <class Dr, class V, class TC, class R, class D>
|
|
Derived operator+ (typename Derived::difference_type n,
|
|
iterator_facade<Dr,V,TC,R,D> const&);
|
|
|
|
|
|
After the ``iterator_facade`` synopsis, add:
|
|
|
|
The ``iterator_category`` member of ``iterator_facade`` is
|
|
|
|
.. parsed-literal::
|
|
|
|
*iterator-category*\ (CategoryOrTraversal, value_type, reference)
|
|
|
|
where *iterator-category* is defined as follows:
|
|
|
|
.. 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*
|
|
|
|
.. |iterator-category| replace:: *iterator-category*
|
|
.. _iterator-category:
|
|
|
|
In [lib.iterator.facade] ``iterator_facade`` requirements:
|
|
|
|
Remove:
|
|
|
|
``AccessCategory`` must be an unsigned value which uses no more
|
|
bits than the greatest value of ``iterator_access``.
|
|
|
|
In the **Iterator Adaptor** section, change:
|
|
|
|
Several of the template parameters of ``iterator_adaptor`` default
|
|
to ``use_default`` (or ``use_default_access``).
|
|
|
|
to:
|
|
|
|
Several of the template parameters of ``iterator_adaptor`` default
|
|
to ``use_default``.
|
|
|
|
In [lib.iterator.special.adaptors]:
|
|
|
|
Change::
|
|
|
|
template <
|
|
class Iterator
|
|
, class Value = use_default
|
|
, unsigned Access = use_default_access
|
|
, class Traversal = use_default
|
|
, class Reference = use_default
|
|
, class Difference = use_default
|
|
>
|
|
class indirect_iterator
|
|
|
|
to::
|
|
|
|
template <
|
|
class Iterator
|
|
, class Value = use_default
|
|
, class CategoryOrTraversal = use_default
|
|
, class Reference = use_default
|
|
, class Difference = use_default
|
|
>
|
|
class indirect_iterator
|
|
|
|
Change::
|
|
|
|
template <
|
|
class Iterator2, class Value2, unsigned Access2, class Traversal2
|
|
, class Reference2, class Difference2
|
|
>
|
|
indirect_iterator(
|
|
|
|
to::
|
|
|
|
template <
|
|
class Iterator2, class Value2, class Category2
|
|
, class Reference2, class Difference2
|
|
>
|
|
indirect_iterator(
|
|
|
|
Change::
|
|
|
|
template <
|
|
class Incrementable
|
|
, unsigned Access = use_default_access
|
|
, class Traversal = use_default
|
|
, class Difference = use_default
|
|
>
|
|
class counting_iterator
|
|
|
|
to::
|
|
|
|
template <
|
|
class Incrementable
|
|
, class CategoryOrTraversal = use_default
|
|
, class Difference = use_default
|
|
>
|
|
class counting_iterator
|
|
|
|
|
|
Change::
|
|
|
|
typedef iterator_tag<
|
|
writable_iterator
|
|
, incrementable_traversal_tag
|
|
> iterator_category;
|
|
|
|
to:
|
|
|
|
typedef std::output_iterator_tag iterator_category;
|
|
|
|
In [lib.iterator.adaptor]
|
|
|
|
Change::
|
|
|
|
template <
|
|
class Derived
|
|
, class Base
|
|
, class Value = use_default
|
|
, unsigned Access = use_default_access
|
|
, class Traversal = use_default
|
|
, class Reference = use_default
|
|
, class Difference = use_default
|
|
>
|
|
class iterator_adaptor
|
|
|
|
To::
|
|
|
|
template <
|
|
class Derived
|
|
, class Base
|
|
, class Value = use_default
|
|
, class CategoryOrTraversal = use_default
|
|
, class Reference = use_default
|
|
, class Difference = use_default
|
|
>
|
|
class iterator_adaptor
|
|
|
|
:Rationale:
|
|
|
|
1. There are two reasons for removing ``is_writable``
|
|
and ``is_swappable``. The first is that we do not know of
|
|
a way to fix the specification so that it gives the correct
|
|
answer for all iterators. Second, there was only a weak
|
|
motivation for having ``is_writable`` and ``is_swappable``
|
|
there in the first place. The main motivation was simply
|
|
uniformity: we have tags for the old iterator categories
|
|
so we should have tags for the new iterator categories.
|
|
While having tags and the capability to dispatch based
|
|
on the traversal categories is often used, we see
|
|
less of a need for dispatching based on writability
|
|
and swappability, since typically algorithms
|
|
that need these capabilities have no alternative if
|
|
they are not provided.
|
|
|
|
2. We discovered that the ``is_readable`` trait can be implemented
|
|
using only the iterator type itself and its ``value_type``.
|
|
Therefore we remove the requirement for ``is_readable`` from the
|
|
Readable Iterator concept, and change the definition of
|
|
``is_readable`` so that it works for any iterator type.
|
|
|
|
3. The purpose of the ``iterator_tag`` class was to bundle the
|
|
traversal and access category tags into the
|
|
``iterator_category`` typedef. With ``is_writable`` and
|
|
``is_swappable`` gone, and ``is_readable`` no longer in need of
|
|
special hints, there is no reason for iterators to provide
|
|
information about the access capabilities of an iterator. Thus
|
|
there is no need for the ``iterator_tag``. The traversal tag can
|
|
be directly used for the ``iterator_category``. If a new
|
|
iterator is intended to be backward compatible with old iterator
|
|
concepts, a tag type that is convertible to both one of the new
|
|
traversal tags and also to an old iterator tag can be created
|
|
and use for the ``iterator_category``.
|
|
|
|
4. The changes to the specification of ``traversal_category`` are a
|
|
direct result of the removal of ``iterator_tag``.
|
|
|
|
|
|
|
|
9.16 is_writable_iterator returns false positives
|
|
=================================================
|
|
|
|
:Submitter: Dave Abrahams
|
|
:Status: New
|
|
|
|
is_writable_iterator returns false positives for forward iterators
|
|
whose value_type has a private assignment operator, or whose
|
|
reference type is not a reference (currently legal).
|
|
|
|
:Proposed Resolution: See the resolution to 9.15.
|
|
|
|
|
|
9.17 is_swappable_iterator returns false positives
|
|
==================================================
|
|
|
|
:Submitter: Dave Abrahams
|
|
:Status: New
|
|
|
|
is_swappable_iterator has the same problems as
|
|
is_writable_iterator. In addition, if we allow users to write their
|
|
own iter_swap functions it's easy to imagine old-style iterators
|
|
for which is_swappable returns false negatives.
|
|
|
|
:Proposed Resolution: See the resolution to 9.15.
|
|
|
|
|
|
9.18 Are is_readable, is_writable, and is_swappable useful?
|
|
===========================================================
|
|
|
|
:Submitter: Dave Abrahams
|
|
:Status: New
|
|
|
|
I am concerned that there is little use for any of is_readable,
|
|
is_writable, or is_swappable, and that not only do they unduly
|
|
constrain iterator implementors but they add overhead to
|
|
iterator_facade and iterator_adaptor in the form of a template
|
|
parameter which would otherwise be unneeded. Since we can't
|
|
implement two of them accurately for old-style iterators, I am
|
|
having a hard time justifying their impact on the rest of the
|
|
proposal(s).
|
|
|
|
:Proposed Resolution: See the resolution to 9.15.
|
|
|
|
9.19 Non-Uniformity of the "lvalue_iterator Bit"
|
|
================================================
|
|
|
|
:Submitter: Dave Abrahams
|
|
:Status: New
|
|
|
|
The proposed iterator_tag class template accepts an "access bits"
|
|
parameter which includes a bit to indicate the iterator's
|
|
lvalueness (whether its dereference operator returns a reference to
|
|
its value_type. The relevant part of N1550 says:
|
|
|
|
The purpose of the lvalue_iterator part of the iterator_access
|
|
enum is to communicate to iterator_tagwhether the reference type
|
|
is an lvalue so that the appropriate old category can be chosen
|
|
for the base class. The lvalue_iterator bit is not recorded in
|
|
the iterator_tag::access data member.
|
|
|
|
The lvalue_iterator bit is not recorded because N1550 aims to
|
|
improve orthogonality of the iterator concepts, and a new-style
|
|
iterator's lvalueness is detectable by examining its reference
|
|
type. This inside/outside difference is awkward and confusing.
|
|
|
|
:Proposed Resolution: The iterator_tag class will be removed, so this is no longer an issue.
|
|
See the resolution to 9.15.
|
|
|
|
|
|
9.20 Traversal Concepts and Tags
|
|
================================
|
|
|
|
:Submitter: Dave Abrahams
|
|
:Status: New
|
|
|
|
Howard Hinnant pointed out some inconsistencies with the naming of
|
|
these tag types::
|
|
|
|
incrementable_iterator_tag // ++r, r++
|
|
single_pass_iterator_tag // adds a == b, a != b
|
|
forward_traversal_iterator_tag // adds multi-pass
|
|
bidirectional_traversal_iterator_tag // adds --r, r--
|
|
random_access_traversal_iterator_tag // adds r+n,n+r,etc.
|
|
|
|
Howard thought that it might be better if all tag names contained
|
|
the word "traversal". It's not clear that would result in the best
|
|
possible names, though. For example, incrementable iterators can
|
|
only make a single pass over their input. What really distinguishes
|
|
single pass iterators from incrementable iterators is not that they
|
|
can make a single pass, but that they are equality
|
|
comparable. Forward traversal iterators really distinguish
|
|
themselves by introducing multi-pass capability. Without entering
|
|
a "Parkinson's Bicycle Shed" type of discussion, it might be worth
|
|
giving the names of these tags (and the associated concepts) some
|
|
extra attention.
|
|
|
|
:Proposed resolution: Change the names of the traversal tags to the
|
|
following names::
|
|
|
|
incrementable_traversal_tag
|
|
single_pass_traversal_tag
|
|
forward_traversal_tag
|
|
bidirectional_traversal_tag
|
|
random_access_traversal_tag
|
|
|
|
|
|
In [lib.iterator.traversal]:
|
|
|
|
|
|
Change:
|
|
|
|
+--------------------------------+-------------------------------+--------------------+
|
|
|``traversal_category<X>::type`` |Convertible to | |
|
|
| |``incrementable_iterator_tag`` | |
|
|
+--------------------------------+-------------------------------+--------------------+
|
|
|
|
to:
|
|
|
|
+--------------------------------+-------------------------------+--------------------+
|
|
|``iterator_traversal<X>::type`` |Convertible to | |
|
|
| |``incrementable_traversal_tag``| |
|
|
+--------------------------------+-------------------------------+--------------------+
|
|
|
|
Change:
|
|
|
|
+--------------------------------+-----------------------------+---------------------------+
|
|
|``traversal_category<X>::type`` |Convertible to | |
|
|
| |``single_pass_iterator_tag`` | |
|
|
+--------------------------------+-----------------------------+---------------------------+
|
|
|
|
to:
|
|
|
|
+--------------------------------+-----------------------------+---------------------------+
|
|
|``iterator_traversal<X>::type`` |Convertible to | |
|
|
| |``single_pass_traversal_tag``| |
|
|
+--------------------------------+-----------------------------+---------------------------+
|
|
|
|
Change:
|
|
|
|
+---------------------------------------+-----------------------------------+---------------+
|
|
|``traversal_category<X>::type`` |Convertible to | |
|
|
| |``forward_traversal_iterator_tag`` | |
|
|
+---------------------------------------+-----------------------------------+---------------+
|
|
|
|
to:
|
|
|
|
+---------------------------------------+-----------------------------------+----------------------------+
|
|
|``iterator_traversal<X>::type`` |Convertible to | |
|
|
| |``forward_traversal_tag`` | |
|
|
+---------------------------------------+-----------------------------------+----------------------------+
|
|
|
|
Change:
|
|
|
|
+------------------------------------+---------------------------------------------+---------------------+
|
|
|``traversal_category<X>::type`` |Convertible to | |
|
|
| |``bidirectional_traversal_iterator_tag`` | |
|
|
+------------------------------------+---------------------------------------------+---------------------+
|
|
|
|
to:
|
|
|
|
+--------------------------------+-------------------------------+---------------------+
|
|
|``iterator_traversal<X>::type`` |Convertible to | |
|
|
| |``bidirectional_traversal_tag``| |
|
|
+--------------------------------+-------------------------------+---------------------+
|
|
|
|
Change:
|
|
|
|
+-------------------------------------------+-------------------------------------------------+-------------------------+----------------------+
|
|
|``traversal_category<X>::type`` |Convertible to | | |
|
|
| |``random_access_traversal_iterator_tag`` | | |
|
|
+-------------------------------------------+-------------------------------------------------+-------------------------+----------------------+
|
|
|
|
to:
|
|
|
|
+-------------------------------+---------------------------------+-------------------------+----------------------+
|
|
|``iterator_traversal<X>::type``|Convertible to | | |
|
|
| |``random_access_traversal_tag`` | | |
|
|
+-------------------------------+---------------------------------+-------------------------+----------------------+
|
|
|
|
|
|
In [lib.iterator.synopsis], change::
|
|
|
|
struct incrementable_iterator_tag { };
|
|
struct single_pass_iterator_tag : incrementable_iterator_tag { };
|
|
struct forward_traversal_tag : single_pass_iterator_tag { };
|
|
|
|
to::
|
|
|
|
struct incrementable_traversal_tag { };
|
|
struct single_pass_traversal_tag : incrementable_traversal_tag { };
|
|
struct forward_traversal_tag : single_pass_traversal_tag { };
|
|
|
|
Remove::
|
|
|
|
struct null_category_tag { };
|
|
struct input_output_iterator_tag : input_iterator_tag, output_iterator_tag {};
|
|
|
|
|
|
9.21 iterator_facade Derived template argument underspecified
|
|
=============================================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
The first template argument to iterator_facade is named Derived,
|
|
and the proposal says:
|
|
|
|
The Derived template parameter must be a class derived from
|
|
iterator_facade.
|
|
|
|
First, iterator_facade is a template, so cannot be derived
|
|
from. Rather, the class must be derived from a specialization of
|
|
iterator_facade. More important, isn't Derived required to be the
|
|
class that is being defined? That is, if I understand it right, the
|
|
definition of D here this is not valid::
|
|
|
|
class C : public iterator_facade<C, ... > { ... };
|
|
class D : public iterator_facade<C, ...> { ... };
|
|
|
|
In the definition of D, the Derived argument to iterator_facade is
|
|
a class derived from a specialization of iterator_facade, so the
|
|
requirement is met. Shouldn't the requirement be more like "when
|
|
using iterator_facade to define an iterator class Iter, the class
|
|
Iter must be derived from a specialization of iterator_facade whose
|
|
first template argument is Iter." That's a bit awkward, but at the
|
|
moment I don't see a better way of phrasing it.
|
|
|
|
:Proposed resolution:
|
|
|
|
In [lib.iterator.facade]
|
|
|
|
Remove:
|
|
|
|
The ``Derived`` template parameter must be a class derived from
|
|
``iterator_facade``.
|
|
|
|
Change:
|
|
|
|
The following table describes the other requirements on the
|
|
``Derived`` parameter. Depending on the resulting iterator's
|
|
``iterator_category``, a subset of the expressions listed in the table
|
|
are required to be valid. The operations in the first column must be
|
|
accessible to member functions of class ``iterator_core_access``.
|
|
|
|
to:
|
|
|
|
The following table describes the typical valid expressions on
|
|
``iterator_facade``\ 's ``Derived`` parameter, depending on the
|
|
iterator concept(s) it will model. The operations in the first
|
|
column must be made accessible to member functions of class
|
|
``iterator_core_access``. In addition,
|
|
``static_cast<Derived*>(iterator_facade*)`` shall be well-formed.
|
|
|
|
In [lib.iterator.adaptor]
|
|
|
|
Change:
|
|
|
|
The ``iterator_adaptor`` is a base class template derived from
|
|
an instantiation of ``iterator_facade``.
|
|
|
|
to:
|
|
|
|
Each specialization of the ``iterator_adaptor`` class template
|
|
is derived from a specialization of ``iterator_facade``.
|
|
|
|
Change:
|
|
|
|
The ``Derived`` template parameter must be a derived class of
|
|
``iterator_adaptor``.
|
|
|
|
To:
|
|
|
|
``static_cast<Derived*>(iterator_adaptor*)`` shall be well-formed.
|
|
|
|
[Note: The proposed resolution to Issue 9.37 contains related
|
|
changes]
|
|
|
|
9.22 return type of Iterator difference for iterator facade
|
|
===========================================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
The proposal says::
|
|
|
|
template <class Dr1, class V1, class AC1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class AC2, class TC2, class R2, class D2>
|
|
typename enable_if_interoperable<Dr1, Dr2, bool>::type
|
|
operator -(iterator_facade<Dr1, V1, AC1, TC1, R1, D1> const& lhs,
|
|
iterator_facade<Dr2, V2, AC2, TC2, R2, D2> const& rhs);
|
|
|
|
Shouldn't the return type be one of the two iterator types? Which
|
|
one? The idea is that if one of the iterator types can be converted
|
|
to the other type, then the subtraction is okay. Seems like the
|
|
return type should then be the type that was converted to. Is that
|
|
right?
|
|
|
|
:Proposed resolution:
|
|
|
|
See resolution to 9.34.
|
|
|
|
9.23 Iterator_facade: minor wording Issue
|
|
=========================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
In the table that lists the required (sort of) member functions of
|
|
iterator types that are based on iterator_facade, the entry for
|
|
c.equal(y) says:
|
|
|
|
true iff c and y refer to the same position. Implements c == y
|
|
and c != y. The second sentence is inside out. c.equal(y) does
|
|
not implement either of these operations. It is used to implement
|
|
them. Same thing in the description of c.distance_to(z).
|
|
|
|
:Proposed resolution: remove "implements" descriptions from
|
|
table. See resolution to 9.34
|
|
|
|
|
|
9.24 Use of undefined name in iterator_facade table
|
|
===================================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
Several of the descriptions use the name X without defining
|
|
it. This seems to be a carryover from the table immediately above
|
|
this section, but the text preceding that table says "In the table
|
|
below, X is the derived iterator type." Looks like the X::
|
|
qualifiers aren't really needed; X::reference can simply be
|
|
reference, since that's defined by the iterator_facade
|
|
specialization itself.
|
|
|
|
:Proposed resolution:
|
|
|
|
Remove references to X.
|
|
|
|
In [lib.iterator.facade] operations ``operator->() const;``:
|
|
|
|
Change:
|
|
|
|
:Returns: If ``X::reference`` is a reference type, an object
|
|
of type ``X::pointer`` equal to::
|
|
|
|
&static_cast<Derived const*>(this)->dereference()
|
|
|
|
Otherwise returns an object of unspecified type such that,
|
|
given an object ``a`` of type ``X``, ``a->m`` is equivalent
|
|
to ``(w = *a, w.m)`` for some temporary object ``w`` of type
|
|
``X::value_type``.
|
|
|
|
The type ``X::pointer`` is ``Value*`` if
|
|
``is_writable_iterator<X>::value`` is ``true``, and
|
|
``Value const*`` otherwise.
|
|
|
|
to:
|
|
|
|
:Returns: If ``reference`` is a reference type, an object
|
|
of type ``pointer`` equal to::
|
|
|
|
&static_cast<Derived const*>(this)->dereference()
|
|
|
|
Otherwise returns an object of unspecified type such that,
|
|
``(*static_cast<Derived const*>(this))->m`` is equivalent
|
|
to ``(w = **static_cast<Derived const*>(this), w.m)`` for
|
|
some temporary object ``w`` of type ``value_type``.
|
|
|
|
Further changes are covered by issue 9.26.
|
|
|
|
9.25 Iterator_facade: wrong return type
|
|
=======================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
Several of the member functions return a Derived object or a
|
|
Derived&. Their Effects clauses end with::
|
|
|
|
return *this;
|
|
|
|
This should be ::
|
|
|
|
return *static_cast<Derived*>(this);
|
|
|
|
:Proposed resolution:
|
|
|
|
In [lib.iterator.facade], in the effects clause
|
|
of the following operations::
|
|
|
|
Derived& operator++()
|
|
Derived& operator--()
|
|
Derived& operator+=(difference_type n)
|
|
Derived& operator-=(difference_type n)
|
|
|
|
Change:
|
|
``return *this``
|
|
|
|
to:
|
|
``return *static_cast<Derived*>(this);``
|
|
|
|
9.26 Iterator_facade: unclear returns clause for operator[]
|
|
===========================================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
The returns clause for ``operator[](difference_type n)`` const
|
|
says:
|
|
|
|
Returns: an object convertible to X::reference and holding a copy
|
|
p of a+n such that, for a constant object v of type
|
|
X::value_type, X::reference(a[n] = v) is equivalent to p = v.
|
|
This needs to define 'a', but assuming it's supposed to be
|
|
``*this`` (or maybe ``*(Derived*)this``), it still isn't clear
|
|
what this says. Presumably, the idea is that you can index off of
|
|
an iterator and assign to the result. But why the requirement
|
|
that it hold a copy of a+n? Granted, that's probably how it's
|
|
implemented, but it seems over-constrained. And the last phrase
|
|
seems wrong. p is an iterator; there's no requirement that you
|
|
can assign a value_type object to it. Should that be ``*p = v``?
|
|
But why the cast in reference(a[n] = v)?
|
|
|
|
:Proposed resolution:
|
|
|
|
In section operator[]:
|
|
|
|
Change:
|
|
|
|
Writable iterators built with ``iterator_facade`` implement
|
|
the semantics required by the preferred resolution to `issue
|
|
299` and adopted by proposal `n1477`: the result of ``p[n]``
|
|
is a proxy object containing a copy of ``p+n``, and ``p[n] =
|
|
x`` is equivalent to ``*(p + n) = x``. This approach will
|
|
work properly for any random-access iterator regardless of
|
|
the other details of its implementation. A user who knows
|
|
more about the implementation of her iterator is free to
|
|
implement an ``operator[]`` which returns an lvalue in the
|
|
derived iterator class; it will hide the one supplied by
|
|
``iterator_facade`` from clients of her iterator.
|
|
|
|
to:
|
|
|
|
Writable iterators built with ``iterator_facade`` implement
|
|
the semantics required by the preferred resolution to `issue
|
|
299` and adopted by proposal `n1550`: the result of ``p[n]``
|
|
is an object convertible to the iterator's ``value_type``,
|
|
and ``p[n] = x`` is equivalent to ``*(p + n) = x`` (Note:
|
|
This result object may be implemented as a proxy containing a
|
|
copy of ``p+n``). This approach will work properly for any
|
|
random-access iterator regardless of the other details of its
|
|
implementation. A user who knows more about the
|
|
implementation of her iterator is free to implement an
|
|
``operator[]`` that returns an lvalue in the derived iterator
|
|
class; it will hide the one supplied by ``iterator_facade``
|
|
from clients of her iterator.
|
|
|
|
In [lib.iterator.facade] operations:
|
|
|
|
Change:
|
|
|
|
:Returns: an object convertible to ``X::reference`` and
|
|
holding a copy *p* of ``a+n`` such that, for a constant
|
|
object ``v`` of type ``X::value_type``, ``X::reference(a[n]
|
|
= v)`` is equivalent to ``p = v``.
|
|
|
|
to:
|
|
|
|
:Returns: an object convertible to ``value_type``. For
|
|
constant objects ``v`` of type ``value_type``, and ``n`` of
|
|
type ``difference_type``, ``(*this)[n] = v`` is equivalent
|
|
to ``*(*this + n) = v``, and ``static_cast<value_type
|
|
const&>((*this)[n])`` is equivalent to
|
|
``static_cast<value_type const&>(*(*this + n))``
|
|
|
|
|
|
9.27 Iterator_facade: redundant clause
|
|
======================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
``operator-`` has both an effects clause and a returns
|
|
clause. Looks like the returns clause should be removed.
|
|
|
|
:Proposed resolution:
|
|
|
|
Remove the returns clause.
|
|
|
|
In [lib.iterator.facade] operations:
|
|
|
|
Remove:
|
|
:Returns: ``static_cast<Derived const*>(this)->advance(-n);``
|
|
|
|
|
|
|
|
|
|
9.28 indirect_iterator: incorrect specification of default constructor
|
|
======================================================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
The default constructor returns "An instance of indirect_iterator
|
|
with a default constructed base object", but the constructor that
|
|
takes an Iterator object returns "An instance of indirect_iterator
|
|
with the iterator_adaptor subobject copy constructed from x." The
|
|
latter is the correct form, since it does not reach inside the base
|
|
class for its semantics. So the default constructor shoudl return
|
|
"An instance of indirect_iterator with a default-constructed
|
|
iterator_adaptor subobject."
|
|
|
|
:Proposed resolution:
|
|
Change:
|
|
:Returns: An instance of ``indirect_iterator`` with
|
|
a default constructed base object.
|
|
|
|
to:
|
|
:Returns: An instance of ``indirect_iterator`` with
|
|
a default-constructed ``m_iterator``.
|
|
|
|
:Rationale: Inheritance from iterator_adaptor has been removed, so we instead
|
|
give the semantics in terms of the (exposition only) member
|
|
``m_iterator``.
|
|
|
|
|
|
9.29 indirect_iterator: unclear specification of template constructor
|
|
=====================================================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
The templated constructor that takes an indirect_iterator with a
|
|
different set of template arguments says that it returns "An
|
|
instance of indirect_iterator that is a copy of [the argument]".
|
|
But the type of the argument is different from the type of the
|
|
object being constructed, and there is no description of what
|
|
a "copy" means. The Iterator template parameter for the argument
|
|
must be convertible to the Iterator template parameter for the type
|
|
being constructed, which suggests that the argument's contained
|
|
Iterator object should be converted to the target type's Iterator
|
|
type. Is that what's meant here?
|
|
(Pete later writes: In fact, this problem is present in all of the
|
|
specialized adaptors that have a constructor like this: the
|
|
constructor returns "a copy" of the argument without saying what a
|
|
copy is.)
|
|
|
|
:Proposed resolution:
|
|
|
|
Change:
|
|
:Returns: An instance of ``indirect_iterator`` that is a copy of ``y``.
|
|
|
|
to:
|
|
:Returns: An instance of ``indirect_iterator`` whose
|
|
``m_iterator`` subobject is constructed from ``y.base()``.
|
|
|
|
|
|
:Rationale: Inheritance from iterator_adaptor has been removed, so we
|
|
instead give the semantics in terms of the member ``m_iterator``.
|
|
|
|
|
|
9.30 transform_iterator argument irregularity
|
|
=============================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
The specialized adaptors that take both a Value and a Reference
|
|
template argument all take them in that order, i.e. Value precedes
|
|
Reference in the template argument list, with the exception of
|
|
transform_iterator, where Reference precedes Value. This seems like
|
|
a possible source of confusion. Is there a reason why this order is
|
|
preferable?
|
|
|
|
:Proposed resolution: NAD
|
|
|
|
:Rationale: defaults for Value depend on Reference. A sensible
|
|
Value can almost always be computed from Reference. The first
|
|
parameter is UnaryFunction, so the argument order is already
|
|
different from the other adapters.
|
|
|
|
|
|
9.31 function_output_iterator overconstrained
|
|
=============================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
function_output_iterator requirements says: "The UnaryFunction must
|
|
be Assignable, Copy Constructible, and the expression f(x) must be
|
|
valid, where f is an object of type UnaryFunction and x is an
|
|
object of a type accepted by f."
|
|
|
|
Everything starting with "and," somewhat reworded, is actually a
|
|
constraint on output_proxy::operator=. All that's needed to create
|
|
a function_output_iterator object is that the UnaryFunction type be
|
|
Assignable and CopyConstructible. That's also sufficient to
|
|
dereference and to increment such an object. It's only when you try
|
|
to assign through a dereferenced iterator that f(x) has to work,
|
|
and then only for the particular function object that the iterator
|
|
holds and for the particular value that is being assigned.
|
|
|
|
|
|
Addition from Jeremy:
|
|
The constructor for ``function_output_iterator`` is also
|
|
slightly overconstrained because it requires
|
|
the ``UnaryFunction`` to have a default constructor
|
|
even when the default constructor of ``function_output_iterator``
|
|
is not used.
|
|
|
|
|
|
:Proposed resolution:
|
|
|
|
Change:
|
|
``output_proxy operator*();``
|
|
|
|
to:
|
|
``/* see below */ operator*();``
|
|
|
|
After ``function_output_iterator& operator++(int);`` add::
|
|
|
|
private:
|
|
UnaryFunction m_f; // exposition only
|
|
|
|
Change:
|
|
The ``UnaryFunction`` must be Assignable, Copy Constructible,
|
|
and the expression ``f(x)`` must be valid, where ``f`` is an
|
|
object of type ``UnaryFunction`` and ``x`` is an object of a
|
|
type accepted by ``f``. The resulting
|
|
``function_output_iterator`` is a model of the Writable and
|
|
Incrementable Iterator concepts.
|
|
|
|
to:
|
|
``UnaryFunction`` must be Assignable and Copy Constructible.
|
|
|
|
After the requirements section, add:
|
|
|
|
.. topic:: ``function_output_iterator`` models
|
|
|
|
``function_output_iterator`` is a model of the Writable and
|
|
Incrementable Iterator concepts.
|
|
|
|
Change:
|
|
:Returns: An instance of ``function_output_iterator`` with
|
|
``f`` stored as a data member.
|
|
|
|
to:
|
|
:Effects: Constructs an instance of ``function_output_iterator``
|
|
with ``m_f`` constructed from ``f``.
|
|
|
|
Change:
|
|
``output_proxy operator*();``
|
|
|
|
:Returns: An instance of ``output_proxy`` constructed with
|
|
a copy of the unary function ``f``.
|
|
|
|
to:
|
|
``operator*();``
|
|
|
|
:Returns: An object ``r`` of unspecified type such that ``r = t``
|
|
is equivalent to ``m_f(t)`` for all ``t``.
|
|
|
|
|
|
Remove:
|
|
``function_output_iterator::output_proxy`` operations
|
|
|
|
``output_proxy(UnaryFunction& f);``
|
|
|
|
:Returns: An instance of ``output_proxy`` with ``f`` stored as
|
|
a data member.
|
|
|
|
|
|
``template <class T> output_proxy& operator=(const T& value);``
|
|
|
|
:Effects:
|
|
::
|
|
|
|
m_f(value);
|
|
return *this;
|
|
|
|
|
|
Change::
|
|
|
|
explicit function_output_iterator(const UnaryFunction& f = UnaryFunction());
|
|
|
|
to::
|
|
|
|
explicit function_output_iterator();
|
|
|
|
explicit function_output_iterator(const UnaryFunction& f);
|
|
|
|
|
|
|
|
9.32 Should output_proxy really be a named type?
|
|
================================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
This means someone can store an output_proxy object for later use,
|
|
whatever that means. It also constrains output_proxy to hold a copy
|
|
of the function object, rather than a pointer to the iterator
|
|
object. Is all this mechanism really necessary?
|
|
|
|
:Proposed resolution: See issue 9.31.
|
|
|
|
|
|
|
|
9.33 istreambuf_iterator isn't a Readable Iterator
|
|
==================================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
c++std-lib-12333:
|
|
|
|
N1550 requires that for a Readable Iterator a of type X, ``*a``
|
|
returns an object of type
|
|
``iterator_traits<X>::reference``. ``istreambuf_iterator::operator*``
|
|
returns ``charT``, but ``istreambuf_iterator::reference`` is
|
|
``charT&``. So am I overlooking something, or is
|
|
``istreambuf_iterator`` not Readable.
|
|
|
|
:Proposed resolution: Remove all constraints on
|
|
``iterator_traits<X>::reference`` in Readable Iterator and Lvalue
|
|
Iterator. Change Lvalue Iterator to refer to ``T&`` instead of
|
|
``iterator_traits<X>::reference``.
|
|
|
|
Change:
|
|
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``.
|
|
|
|
to:
|
|
A class or built-in type ``X`` models the *Readable Iterator*
|
|
concept for value type ``T`` if, in addition to ``X`` being
|
|
Assignable and Copy Constructible, the following expressions
|
|
are valid and respect the stated semantics. ``U`` is the type
|
|
of any specified member of type ``T``.
|
|
|
|
From the Input Iterator Requirements table, remove:
|
|
|
|
+-----------------------------------+-----------------------------------+-------------------------+
|
|
|``iterator_traits<X>::reference`` |Convertible to | |
|
|
| |``iterator_traits<X>::value_type`` | |
|
|
+-----------------------------------+-----------------------------------+-------------------------+
|
|
|
|
Change:
|
|
|
|
+-----------------------------------+-----------------------------------+-------------------------+
|
|
|``*a`` |``iterator_traits<X>::reference`` |pre: ``a`` is |
|
|
| | |dereferenceable. If ``a |
|
|
| | |== b`` then ``*a`` is |
|
|
| | |equivalent to ``*b`` |
|
|
+-----------------------------------+-----------------------------------+-------------------------+
|
|
|
|
to:
|
|
|
|
+-----------------------------------+------------------------+----------------------------------------------------------------+
|
|
|``*a`` | Convertible to ``T`` |pre: ``a`` is dereferenceable. If ``a == b`` then ``*a`` |
|
|
| | | is equivalent to ``*b``. |
|
|
+-----------------------------------+------------------------+----------------------------------------------------------------+
|
|
|
|
Change:
|
|
The *Lvalue Iterator* concept adds the requirement that the
|
|
``reference`` type be a reference to the value type of the
|
|
iterator.
|
|
|
|
to:
|
|
The *Lvalue Iterator* concept adds the requirement that the
|
|
return type of ``operator*`` type be a reference to the value
|
|
type of the iterator.
|
|
|
|
Change:
|
|
|
|
+---------------------------------------------------------------------------------+
|
|
| Lvalue Iterator Requirements |
|
|
+---------------------------------+-----------+-----------------------------------+
|
|
|Expression |Return Type|Assertion |
|
|
+=================================+===========+===================================+
|
|
|``iterator_traits<X>::reference``|``T&`` |``T`` is *cv* |
|
|
| | |``iterator_traits<X>::value_type`` |
|
|
| | |where *cv* is an optional |
|
|
| | |cv-qualification |
|
|
+---------------------------------+-----------+-----------------------------------+
|
|
|
|
to:
|
|
|
|
+-------------------------------------------------------------+
|
|
| Lvalue Iterator Requirements |
|
|
+-------------+-----------+-----------------------------------+
|
|
|Expression |Return Type|Note/Assertion |
|
|
+=============+===========+===================================+
|
|
|``*a`` | ``T&`` |``T`` is *cv* |
|
|
| | |``iterator_traits<X>::value_type`` |
|
|
| | |where *cv* is an optional |
|
|
| | |cv-qualification. |
|
|
| | |pre: ``a`` is |
|
|
| | |dereferenceable. If ``a |
|
|
| | |== b`` then ``*a`` is |
|
|
| | |equivalent to ``*b``. |
|
|
+-------------+-----------+-----------------------------------+
|
|
|
|
|
|
At the end of the section reverse_iterator models, add:
|
|
The type ``iterator_traits<Iterator>::reference`` must be the type of
|
|
``*i``, where ``i`` is an object of type ``Iterator``.
|
|
|
|
|
|
:Rationale: Ideally there should be requirements on the reference
|
|
type, however, since Readable Iterator is suppose to correspond
|
|
to the current standard iterator requirements (which do not place
|
|
requirements on the reference type) we will leave them off for
|
|
now. There is a DR in process with respect to the reference type
|
|
in the stadard iterator requirements. Once that is resolved we
|
|
will revisit this issue for Readable Iterator and Lvalue
|
|
Iterator.
|
|
|
|
We added Assignable to the requirements for Readable
|
|
Iterator. This is needed to have Readable Iterator coincide with
|
|
the capabilities of Input Iterator.
|
|
|
|
|
|
9.34 iterator_facade free functions unspecified
|
|
===============================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
c++std-lib-12562:
|
|
|
|
The template functions ``operator==``, ``operator!=``,
|
|
``operator<``, ``operator<=``, ``operator>``, ``operator>=``, and
|
|
``operator-`` that take two arguments that are specializations of
|
|
iterator_facade have no specification. The template function
|
|
operator+ that takes an argument that is a specialization of
|
|
iterator_facade and an argument of type difference_type has no
|
|
specification.
|
|
|
|
:Proposed resolution:
|
|
Add the missing specifications.
|
|
|
|
::
|
|
|
|
template <class Dr, class V, class TC, class R, class D>
|
|
Derived operator+ (iterator_facade<Dr,V,TC,R,D> const&,
|
|
typename Derived::difference_type n);
|
|
|
|
template <class Dr, class V, class TC, class R, class D>
|
|
Derived operator+ (typename Derived::difference_type n,
|
|
iterator_facade<Dr,V,TC,R,D> const&);
|
|
|
|
:Effects:
|
|
::
|
|
|
|
Derived tmp(static_cast<Derived const*>(this));
|
|
return tmp += n;
|
|
|
|
|
|
::
|
|
|
|
template <class Dr1, class V1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class TC2, class R2, class D2>
|
|
typename enable_if_interoperable<Dr1,Dr2,bool>::type
|
|
operator ==(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
|
|
iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
|
|
|
|
:Returns: if ``is_convertible<Dr2,Dr1>::value``, then
|
|
``lhs.equal(rhs)``. Otherwise, ``rhs.equal(lhs)``.
|
|
|
|
::
|
|
|
|
template <class Dr1, class V1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class TC2, class R2, class D2>
|
|
typename enable_if_interoperable<Dr1,Dr2,bool>::type
|
|
operator !=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
|
|
iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
|
|
|
|
:Returns: if ``is_convertible<Dr2,Dr1>::value``, then
|
|
``!lhs.equal(rhs)``. Otherwise, ``!rhs.equal(lhs)``.
|
|
|
|
::
|
|
|
|
template <class Dr1, class V1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class TC2, class R2, class D2>
|
|
typename enable_if_interoperable<Dr1,Dr2,bool>::type
|
|
operator <(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
|
|
iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
|
|
|
|
:Returns: if ``is_convertible<Dr2,Dr1>::value``, then
|
|
``lhs.distance_to(rhs) < 0``. Otherwise, ``rhs.distance_to(lhs) >
|
|
0``.
|
|
|
|
::
|
|
|
|
template <class Dr1, class V1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class TC2, class R2, class D2>
|
|
typename enable_if_interoperable<Dr1,Dr2,bool>::type
|
|
operator <=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
|
|
iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
|
|
|
|
:Returns: if ``is_convertible<Dr2,Dr1>::value``, then
|
|
``lhs.distance_to(rhs) <= 0``. Otherwise, ``rhs.distance_to(lhs)
|
|
>= 0``.
|
|
|
|
::
|
|
|
|
template <class Dr1, class V1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class TC2, class R2, class D2>
|
|
typename enable_if_interoperable<Dr1,Dr2,bool>::type
|
|
operator >(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
|
|
iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
|
|
|
|
:Returns: if ``is_convertible<Dr2,Dr1>::value``, then
|
|
``lhs.distance_to(rhs) > 0``. Otherwise,
|
|
``rhs.distance_to(lhs) < 0``.
|
|
|
|
|
|
::
|
|
|
|
template <class Dr1, class V1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class TC2, class R2, class D2>
|
|
typename enable_if_interoperable<Dr1,Dr2,bool>::type
|
|
operator >=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
|
|
iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
|
|
|
|
:Returns: if ``is_convertible<Dr2,Dr1>::value``, then
|
|
``lhs.distance_to(rhs) >= 0``. Otherwise,
|
|
``rhs.distance_to(lhs) <= 0``.
|
|
|
|
::
|
|
|
|
template <class Dr1, class V1, class TC1, class R1, class D1,
|
|
class Dr2, class V2, class TC2, class R2, class D2>
|
|
typename enable_if_interoperable<Dr1,Dr2,difference>::type
|
|
operator -(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs,
|
|
iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs);
|
|
|
|
:Return Type: if ``is_convertible<Dr2,Dr1>::value``, then
|
|
``difference`` shall be
|
|
``iterator_traits<Dr1>::difference_type``. Otherwise,
|
|
``difference`` shall be
|
|
``iterator_traits<Dr2>::difference_type``.
|
|
|
|
:Returns: if ``is_convertible<Dr2,Dr1>::value``, then
|
|
``-lhs.distance_to(rhs)``. Otherwise,
|
|
``rhs.distance_to(lhs)``.
|
|
|
|
|
|
|
|
9.35 iterator_facade: too many equals?
|
|
======================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
c++std-lib-12563:
|
|
|
|
The table listing the functions required for types derived from
|
|
iterator_facade has two functions named equal and two named
|
|
distance_to::
|
|
|
|
c.equal(b)
|
|
c.equal(y)
|
|
c.distance_to(b)
|
|
c.distance_to(z)
|
|
|
|
where b and c are const objects of the derived type, y and z are
|
|
constant objects of certain iterator types that are interoperable
|
|
with the derived type. Seems like the 'b' versions are
|
|
redundant: in both cases, the other version will take a 'b'. In
|
|
fact, iterator_adaptor is specified to use iterator_facade, but
|
|
does not provide the 'b' versions of these functions.
|
|
|
|
Are the 'b' versions needed?
|
|
|
|
:Proposed resolution: Remove the 'b' versions.
|
|
|
|
In ``iterator_facade`` requirements, remove:
|
|
|
|
+--------------------+-------------------+-------------------------------------+---------------------------+
|
|
|``c.equal(b)`` |convertible to bool|true iff ``b`` and ``c`` are |Single Pass Iterator |
|
|
| | |equivalent. | |
|
|
+--------------------+-------------------+-------------------------------------+---------------------------+
|
|
|
|
and remove:
|
|
|
|
+--------------------+-------------------+-------------------------------------+---------------------------+
|
|
|``c.distance_to(b)``|convertible to |equivalent to ``distance(c, b)`` |Random Access Traversal |
|
|
| |X::difference_type | |Iterator |
|
|
+--------------------+-------------------+-------------------------------------+---------------------------+
|
|
|
|
|
|
9.36 iterator_facade function requirements
|
|
==========================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
c++std-lib-12636:
|
|
|
|
The table that lists required functions for the derived type X
|
|
passed to iterator_facade lists, among others:
|
|
|
|
for a single pass iterator::
|
|
|
|
c.equal(b)
|
|
c.equal(y)
|
|
|
|
where b and c are const X objects, and y is a const object of a
|
|
single pass iterator that is interoperable with X. Since X is
|
|
interoperable with itself, c.equal(b) is redundant. There is a
|
|
difference in their descriptions, but its meaning isn't
|
|
clear. The first is "true iff b and c are equivalent", and the
|
|
second is "true iff c and y refer to the same position." Is there
|
|
a difference between the undefined term "equivalent" and "refer
|
|
to the same position"?
|
|
|
|
Similarly, for a random access traversal iterator::
|
|
|
|
c.distance_to(b)
|
|
c.distance_to(z)
|
|
|
|
where z is a constant object of a random access traversal
|
|
iterator that is interoperable with X. Again, X is interoperable
|
|
with itself, so c.distance_to(b) is redundant. Also, the
|
|
specification for c.distance_to(z) isn't valid. It's written
|
|
as "equivalent to distance(c, z)". The template function distance
|
|
takes two arguments of the same type, so distance(c, z) isn't
|
|
valid if c and z are different types. Should it be
|
|
distance(c, (X)z)?
|
|
|
|
:Proposed resolution: Removed the 'b' versions (see 9.35) and added the cast.
|
|
|
|
Change:
|
|
|
|
+--------------------+-------------------+-------------------------------------+---------------------------+
|
|
|``c.distance_to(z)``|convertible to |equivalent to ``distance(c, z)``. |Random Access Traversal |
|
|
| |X::difference_type |Implements ``c - z``, ``c < z``, ``c |Iterator |
|
|
| | |<= z``, ``c > z``, and ``c >= c``. | |
|
|
+--------------------+-------------------+-------------------------------------+---------------------------+
|
|
|
|
to:
|
|
|
|
+--------------------+----------------------+-------------------------+---------------------------+
|
|
|``c.distance_to(z)``|convertible to |equivalent to |Random Access Traversal |
|
|
| |``F::difference_type``|``distance(c, X(z))``. |Iterator |
|
|
+--------------------+----------------------+-------------------------+---------------------------+
|
|
|
|
|
|
|
|
====================================
|
|
More Issues (not from Matt's list)
|
|
====================================
|
|
|
|
|
|
|
|
9.37x Inheritance in iterator_adaptor and other adaptors is an overspecification
|
|
================================================================================
|
|
|
|
:Submitter: Pete Becker
|
|
:Status: New
|
|
|
|
c++std-lib-12696:
|
|
The paper requires that iterator_adaptor be derived from an
|
|
appropriate instance of iterator_facade, and that most of the specific
|
|
forms of adaptors be derived from appropriate instances of
|
|
iterator_adaptor. That seems like overspecification, and we ought to
|
|
look at specifying these things in terms of what the various templates
|
|
provide rather than how they're implemented.
|
|
|
|
:Proposed resolution:
|
|
|
|
Remove the specfication of inheritance, and add explicit
|
|
specification of all the functionality that was inherited from the
|
|
specialized iterators.
|
|
|
|
In iterator_adaptor, inheritance is retained, sorry NAD. Also,
|
|
the Interoperable Iterators concept is added to the new iterator
|
|
concepts, and this concept is used in the specification of the
|
|
iterator adaptors.
|
|
|
|
|
|
In n1550, after [lib.random.access.traversal.iterators], add:
|
|
|
|
Interoperable Iterators [lib.interoperable.iterators]
|
|
|
|
A class or built-in type ``X`` that models Single Pass Iterator
|
|
is *interoperable with* a class or built-in type ``Y`` that
|
|
also models Single Pass Iterator if the following expressions
|
|
are valid and respect the stated semantics. In the tables
|
|
below, ``x`` is an object of type ``X``, ``y`` is an object of
|
|
type ``Y``, ``Distance`` is
|
|
``iterator_traits<Y>::difference_type``, and ``n`` represents a
|
|
constant object of type ``Distance``.
|
|
|
|
+-----------+-----------------------+---------------------------------------------------+
|
|
|Expression |Return Type |Assertion/Precondition/Postcondition |
|
|
+===========+=======================+===================================================+
|
|
|``y = x`` |``Y`` |post: ``y == x`` |
|
|
+-----------+-----------------------+---------------------------------------------------+
|
|
|``Y(x)`` |``Y`` |post: ``Y(x) == x`` |
|
|
+-----------+-----------------------+---------------------------------------------------+
|
|
|``x == y`` |convertible to ``bool``|``==`` is an equivalence relation over its domain. |
|
|
+-----------+-----------------------+---------------------------------------------------+
|
|
|``y == x`` |convertible to ``bool``|``==`` is an equivalence relation over its domain. |
|
|
+-----------+-----------------------+---------------------------------------------------+
|
|
|``x != y`` |convertible to ``bool``|``bool(a==b) != bool(a!=b)`` over its domain. |
|
|
+-----------+-----------------------+---------------------------------------------------+
|
|
|``y != x`` |convertible to ``bool``|``bool(a==b) != bool(a!=b)`` over its domain. |
|
|
+-----------+-----------------------+---------------------------------------------------+
|
|
|
|
If ``X`` and ``Y`` both model Random Access Traversal Iterator then
|
|
the following additional requirements must be met.
|
|
|
|
+-----------+-----------------------+---------------------+--------------------------------------+
|
|
|Expression |Return Type |Operational Semantics|Assertion/ Precondition |
|
|
+===========+=======================+=====================+======================================+
|
|
|``x < y`` |convertible to ``bool``|``y - x > 0`` |``<`` is a total ordering relation |
|
|
+-----------+-----------------------+---------------------+--------------------------------------+
|
|
|``y < x`` |convertible to ``bool``|``x - y > 0`` |``<`` is a total ordering relation |
|
|
+-----------+-----------------------+---------------------+--------------------------------------+
|
|
|``x > y`` |convertible to ``bool``|``y < x`` |``>`` is a total ordering relation |
|
|
+-----------+-----------------------+---------------------+--------------------------------------+
|
|
|``y > x`` |convertible to ``bool``|``x < y`` |``>`` is a total ordering relation |
|
|
+-----------+-----------------------+---------------------+--------------------------------------+
|
|
|``x >= y`` |convertible to ``bool``|``!(x < y)`` | |
|
|
+-----------+-----------------------+---------------------+--------------------------------------+
|
|
|``y >= x`` |convertible to ``bool``|``!(y < x)`` | |
|
|
+-----------+-----------------------+---------------------+--------------------------------------+
|
|
|``x <= y`` |convertible to ``bool``|``!(x > y)`` | |
|
|
+-----------+-----------------------+---------------------+--------------------------------------+
|
|
|``y <= x`` |convertible to ``bool``|``!(y > x)`` | |
|
|
+-----------+-----------------------+---------------------+--------------------------------------+
|
|
|``y - x`` |``Distance`` |``distance(Y(x),y)`` |pre: there exists a value ``n`` of |
|
|
| | | |``Distance`` such that ``x + n == y``.|
|
|
| | | |``y == x + (y - x)``. |
|
|
+-----------+-----------------------+---------------------+--------------------------------------+
|
|
|``x - y`` |``Distance`` |``distance(y,Y(x))`` |pre: there exists a value ``n`` of |
|
|
| | | |``Distance`` such that ``y + n == x``.|
|
|
| | | |``x == y + (x - y)``. |
|
|
+-----------+-----------------------+---------------------+--------------------------------------+
|
|
|
|
|
|
|
|
In N1530:
|
|
|
|
In [lib.iterator.adaptor]
|
|
|
|
Change::
|
|
|
|
class iterator_adaptor
|
|
: public iterator_facade<Derived, /* see details ...*/>
|
|
|
|
To::
|
|
|
|
class iterator_adaptor
|
|
: public iterator_facade<Derived, *V'*, *C'*, *R'*, *D'*> // see details
|
|
|
|
|
|
Change the text from:
|
|
The ``Base`` type must implement the expressions involving
|
|
``m_iterator`` in the specifications...
|
|
|
|
until the end of the **iterator_adaptor requirements** section, to:
|
|
The ``Base`` argument shall be Assignable and Copy Constructible.
|
|
|
|
|
|
Add:
|
|
|
|
.. topic:: ``iterator_adaptor`` base class parameters
|
|
|
|
The *V'*, *C'*, *R'*, and *D'* parameters of the ``iterator_facade``
|
|
used as a base class in the summary of ``iterator_adaptor``
|
|
above are defined as follows:
|
|
|
|
.. parsed-literal::
|
|
|
|
*V'* = if (Value is use_default)
|
|
return iterator_traits<Base>::value_type
|
|
else
|
|
return Value
|
|
|
|
*C'* = if (CategoryOrTraversal is use_default)
|
|
return iterator_traversal<Base>::type
|
|
else
|
|
return CategoryOrTraversal
|
|
|
|
*R'* = if (Reference is use_default)
|
|
if (Value is use_default)
|
|
return iterator_traits<Base>::reference
|
|
else
|
|
return Value&
|
|
else
|
|
return Reference
|
|
|
|
*D'* = if (Difference is use_default)
|
|
return iterator_traits<Base>::difference_type
|
|
else
|
|
return Difference
|
|
|
|
|
|
In [lib.iterator.special.adaptors]
|
|
|
|
Change::
|
|
|
|
class indirect_iterator
|
|
: public iterator_adaptor</* see discussion */>
|
|
{
|
|
friend class iterator_core_access;
|
|
|
|
to::
|
|
|
|
class indirect_iterator
|
|
{
|
|
public:
|
|
typedef /* see below */ value_type;
|
|
typedef /* see below */ reference;
|
|
typedef /* see below */ pointer;
|
|
typedef /* see below */ difference_type;
|
|
typedef /* see below */ iterator_category;
|
|
|
|
Change::
|
|
|
|
private: // as-if specification
|
|
typename indirect_iterator::reference dereference() const
|
|
{
|
|
return **this->base();
|
|
}
|
|
|
|
to::
|
|
|
|
Iterator const& base() const;
|
|
reference operator*() const;
|
|
indirect_iterator& operator++();
|
|
indirect_iterator& operator--();
|
|
private:
|
|
Iterator m_iterator; // exposition
|
|
|
|
|
|
After the synopsis add:
|
|
|
|
The member types of ``indirect_iterator`` are defined
|
|
according to the following pseudo-code, where ``V`` is
|
|
``iterator_traits<Iterator>::value_type``
|
|
|
|
.. parsed-literal::
|
|
|
|
if (Value is use_default) then
|
|
typedef remove_const<pointee<V>::type>::type value_type;
|
|
else
|
|
typedef remove_const<Value>::type value_type;
|
|
|
|
if (Reference is use_default) then
|
|
if (Value is use_default) then
|
|
typedef indirect_reference<V>::type reference;
|
|
else
|
|
typedef Value& reference;
|
|
else
|
|
typedef Reference reference;
|
|
|
|
if (Value is use_default) then
|
|
typedef pointee<V>::type\* pointer;
|
|
else
|
|
typedef Value\* pointer;
|
|
|
|
if (Difference is use_default)
|
|
typedef iterator_traits<Iterator>::difference_type difference_type;
|
|
else
|
|
typedef Difference difference_type;
|
|
|
|
if (CategoryOrTraversal is use_default)
|
|
typedef |iterator-category|\ (
|
|
iterator_traversal<Iterator>::type,``reference``,``value_type``
|
|
) iterator_category;
|
|
else
|
|
typedef |iterator-category|\ (
|
|
CategoryOrTraversal,``reference``,``value_type``
|
|
) iterator_category;
|
|
|
|
|
|
[Note: See resolution to 9.44y for a description of ``pointee`` and
|
|
``indirect_reference``]
|
|
|
|
After the requirements section, add:
|
|
|
|
.. topic:: ``indirect_iterator`` models
|
|
|
|
|
|
In addition to the concepts indicated by ``iterator_category``
|
|
and by ``iterator_traversal<indirect_iterator>::type``, a
|
|
specialization of ``indirect_iterator`` models the following
|
|
concepts, Where ``v`` is an object of
|
|
``iterator_traits<Iterator>::value_type``:
|
|
|
|
* Readable Iterator if ``reference(*v)`` is convertible to
|
|
``value_type``.
|
|
|
|
* Writable Iterator if ``reference(*v) = t`` is a valid
|
|
expression (where ``t`` is an object of type
|
|
``indirect_iterator::value_type``)
|
|
|
|
* Lvalue Iterator if ``reference`` is a reference type.
|
|
|
|
``indirect_iterator<X,V1,C1,R1,D1>`` is interoperable with
|
|
``indirect_iterator<Y,V2,C2,R2,D2>`` if and only if ``X`` is
|
|
interoperable with ``Y``.
|
|
|
|
|
|
Before ``indirect_iterator();`` add:
|
|
|
|
In addition to the operations required by the concepts described
|
|
above, specializations of ``indirect_iterator`` provide the
|
|
following operations.
|
|
|
|
Change:
|
|
:Returns: An instance of ``indirect_iterator`` with
|
|
the ``iterator_adaptor`` subobject copy constructed from ``x``.
|
|
|
|
to:
|
|
:Returns: An instance of ``indirect_iterator`` with
|
|
``m_iterator`` copy constructed from ``x``.
|
|
|
|
|
|
At the end of the indirect_iterator operations add:
|
|
|
|
``Iterator const& base() const;``
|
|
|
|
:Returns: ``m_iterator``
|
|
|
|
|
|
``reference operator*() const;``
|
|
|
|
:Returns: ``**m_iterator``
|
|
|
|
|
|
``indirect_iterator& operator++();``
|
|
|
|
:Effects: ``++m_iterator``
|
|
:Returns: ``*this``
|
|
|
|
|
|
``indirect_iterator& operator--();``
|
|
|
|
:Effects: ``--m_iterator``
|
|
:Returns: ``*this``
|
|
|
|
|
|
|
|
Change::
|
|
|
|
template <class Iterator>
|
|
class reverse_iterator :
|
|
public iterator_adaptor< reverse_iterator<Iterator>, Iterator >
|
|
{
|
|
friend class iterator_core_access;
|
|
|
|
to::
|
|
|
|
template <class Iterator>
|
|
class reverse_iterator
|
|
{
|
|
public:
|
|
typedef iterator_traits<Iterator>::value_type value_type;
|
|
typedef iterator_traits<Iterator>::reference reference;
|
|
typedef iterator_traits<Iterator>::pointer pointer;
|
|
typedef iterator_traits<Iterator>::difference_type difference_type;
|
|
typedef /* see below */ iterator_category;
|
|
|
|
Change::
|
|
|
|
private: // as-if specification
|
|
typename reverse_iterator::reference dereference() const { return *prior(this->base()); }
|
|
|
|
void increment() { --this->base_reference(); }
|
|
void decrement() { ++this->base_reference(); }
|
|
|
|
void advance(typename reverse_iterator::difference_type n)
|
|
{
|
|
this->base_reference() += -n;
|
|
}
|
|
|
|
template <class OtherIterator>
|
|
typename reverse_iterator::difference_type
|
|
distance_to(reverse_iterator<OtherIterator> const& y) const
|
|
{
|
|
return this->base_reference() - y.base();
|
|
}
|
|
|
|
to::
|
|
|
|
Iterator const& base() const;
|
|
reference operator*() const;
|
|
reverse_iterator& operator++();
|
|
reverse_iterator& operator--();
|
|
private:
|
|
Iterator m_iterator; // exposition
|
|
|
|
After the synopsis for ``reverse_iterator``, add:
|
|
If ``Iterator`` models Random Access Traversal Iterator and Readable
|
|
Lvalue Iterator, then ``iterator_category`` is convertible to
|
|
``random_access_iterator_tag``. Otherwise, if
|
|
``Iterator`` models Bidirectional Traversal Iterator and Readable
|
|
Lvalue Iterator, then ``iterator_category`` is convertible to
|
|
``bidirectional_iterator_tag``. Otherwise, ``iterator_category`` is
|
|
convertible to ``input_iterator_tag``.
|
|
|
|
|
|
Change:
|
|
**reverse_iterator requirements**
|
|
|
|
The base ``Iterator`` must be a model of Bidirectional Traversal
|
|
Iterator. The resulting ``reverse_iterator`` will be a model of the
|
|
most refined standard traversal and access concepts that are modeled
|
|
by ``Iterator``.
|
|
|
|
|
|
to:
|
|
**reverse_iterator requirements**
|
|
|
|
``Iterator`` must be a model of Bidirectional Traversal Iterator.
|
|
|
|
|
|
.. topic:: ``reverse_iterator`` models
|
|
|
|
A specialization of ``reverse_iterator`` models the same iterator
|
|
traversal and iterator access concepts modeled by its ``Iterator``
|
|
argument. In addition, it may model old iterator concepts
|
|
specified in the following table:
|
|
|
|
+---------------------------------------+-----------------------------------+
|
|
| If ``I`` models |then ``reverse_iterator<I>`` models|
|
|
+=======================================+===================================+
|
|
| Readable Lvalue Iterator, | Bidirectional Iterator |
|
|
| Bidirectional Traversal Iterator | |
|
|
+---------------------------------------+-----------------------------------+
|
|
| Writable Lvalue Iterator, | Mutable Bidirectional Iterator |
|
|
| Bidirectional Traversal Iterator | |
|
|
+---------------------------------------+-----------------------------------+
|
|
| Readable Lvalue Iterator, | Random Access Iterator |
|
|
| Random Access Traversal Iterator | |
|
|
+---------------------------------------+-----------------------------------+
|
|
| Writable Lvalue Iterator, | Mutable Random Access Iterator |
|
|
| Random Access Traversal Iterator | |
|
|
+---------------------------------------+-----------------------------------+
|
|
|
|
|
|
``reverse_iterator<X>`` is interoperable with
|
|
``reverse_iterator<Y>`` if and only if ``X`` is interoperable with
|
|
``Y``.
|
|
|
|
Change:
|
|
:Returns: An instance of ``reverse_iterator`` with a
|
|
default constructed base object.
|
|
|
|
to:
|
|
:Effects: Constructs an instance of ``reverse_iterator`` with ``m_iterator``
|
|
default constructed.
|
|
|
|
Change:
|
|
:Effects: Constructs an instance of ``reverse_iterator`` with a
|
|
base object copy constructed from ``x``.
|
|
|
|
to:
|
|
:Effects: Constructs an instance of ``reverse_iterator`` with a
|
|
``m_iterator`` constructed from ``x``.
|
|
|
|
|
|
Change:
|
|
:Returns: An instance of ``reverse_iterator`` that is a copy of ``r``.
|
|
|
|
to:
|
|
:Effects: Constructs instance of ``reverse_iterator`` whose
|
|
``m_iterator`` subobject is constructed from ``y.base()``.
|
|
|
|
|
|
|
|
At the end of the operations for ``reverse_iterator``, add:
|
|
``Iterator const& base() const;``
|
|
|
|
:Returns: ``m_iterator``
|
|
|
|
|
|
``reference operator*() const;``
|
|
|
|
:Effects:
|
|
|
|
::
|
|
|
|
Iterator tmp = m_iterator;
|
|
return *--tmp;
|
|
|
|
|
|
``reverse_iterator& operator++();``
|
|
|
|
:Effects: ``--m_iterator``
|
|
:Returns: ``*this``
|
|
|
|
|
|
``reverse_iterator& operator--();``
|
|
|
|
:Effects: ``++m_iterator``
|
|
:Returns: ``*this``
|
|
|
|
|
|
|
|
Change::
|
|
|
|
class transform_iterator
|
|
: public iterator_adaptor</* see discussion */>
|
|
{
|
|
friend class iterator_core_access;
|
|
|
|
to::
|
|
|
|
class transform_iterator
|
|
{
|
|
public:
|
|
typedef /* see below */ value_type;
|
|
typedef /* see below */ reference;
|
|
typedef /* see below */ pointer;
|
|
typedef iterator_traits<Iterator>::difference_type difference_type;
|
|
typedef /* see below */ iterator_category;
|
|
|
|
|
|
After ``UnaryFunction functor() const;`` add::
|
|
|
|
Iterator const& base() const;
|
|
reference operator*() const;
|
|
transform_iterator& operator++();
|
|
transform_iterator& operator--();
|
|
|
|
Change::
|
|
|
|
private:
|
|
typename transform_iterator::value_type dereference() const;
|
|
UnaryFunction m_f;
|
|
};
|
|
|
|
to::
|
|
|
|
private:
|
|
Iterator m_iterator; // exposition only
|
|
UnaryFunction m_f; // exposition only
|
|
};
|
|
|
|
|
|
After the synopsis, add:
|
|
If ``Iterator`` models Readable Lvalue Iterator and if ``Iterator``
|
|
models Random Access Traversal Iterator, then ``iterator_category`` is
|
|
convertible to ``random_access_iterator_tag``. Otherwise, if
|
|
``Iterator`` models Bidirectional Traversal Iterator, then
|
|
``iterator_category`` is convertible to
|
|
``bidirectional_iterator_tag``. Otherwise ``iterator_category`` is
|
|
convertible to ``forward_iterator_tag``. If ``Iterator`` does not
|
|
model Readable Lvalue Iterator then ``iterator_category`` is
|
|
convertible to ``input_iterator_tag``.
|
|
|
|
|
|
In the requirements section, change:
|
|
The type ``Iterator`` must at least model Readable Iterator. The
|
|
resulting ``transform_iterator`` models the most refined of the
|
|
following that is also modeled by ``Iterator``.
|
|
|
|
* Writable Lvalue Iterator if
|
|
``result_of<UnaryFunction(iterator_traits<Iterator>::reference)>::type``
|
|
is a non-const reference.
|
|
|
|
* Readable Lvalue Iterator if
|
|
``result_of<UnaryFunction(iterator_traits<Iterator>::reference)>::type``
|
|
is a const reference.
|
|
|
|
* Readable Iterator otherwise.
|
|
|
|
|
|
The ``transform_iterator`` models the most refined standard traversal
|
|
concept that is modeled by ``Iterator``.
|
|
|
|
The ``reference`` type of ``transform_iterator`` is
|
|
``result_of<UnaryFunction(iterator_traits<Iterator>::reference)>::type``.
|
|
The ``value_type`` is ``remove_cv<remove_reference<reference> >::type``.
|
|
|
|
to:
|
|
The argument ``Iterator`` shall model Readable Iterator.
|
|
|
|
|
|
After the requirements section, add:
|
|
|
|
.. topic:: ``transform_iterator`` models
|
|
|
|
The resulting ``transform_iterator`` models the most refined of the
|
|
following options that is also modeled by ``Iterator``.
|
|
|
|
* Writable Lvalue Iterator if
|
|
``transform_iterator::reference`` is a non-const
|
|
reference.
|
|
|
|
* Readable Lvalue Iterator if
|
|
``transform_iterator::reference`` is a const reference.
|
|
|
|
* Readable Iterator otherwise.
|
|
|
|
The ``transform_iterator`` models the most refined standard traversal
|
|
concept that is modeled by the ``Iterator`` argument.
|
|
|
|
If ``transform_iterator`` is a model of Readable Lvalue Iterator then
|
|
it models the following original iterator concepts depending on what
|
|
the ``Iterator`` argument models.
|
|
|
|
+-----------------------------------+-----------------------------------+
|
|
| If ``Iterator`` models |then ``transform_iterator`` models |
|
|
+===================================+===================================+
|
|
| Single Pass Iterator | Input Iterator |
|
|
+-----------------------------------+-----------------------------------+
|
|
| Forward Traversal Iterator | Forward Iterator |
|
|
+-----------------------------------+-----------------------------------+
|
|
| Bidirectional Traversal Iterator | Bidirectional Iterator |
|
|
+-----------------------------------+-----------------------------------+
|
|
| Random Access Traversal Iterator | Random Access Iterator |
|
|
+-----------------------------------+-----------------------------------+
|
|
|
|
If ``transform_iterator`` models Writable Lvalue Iterator then it is a
|
|
mutable iterator (as defined in the old iterator requirements).
|
|
|
|
``transform_iterator<F1, X, R1, V1>`` is interoperable with
|
|
``transform_iterator<F2, Y, R2, V2>`` if and only if ``X`` is
|
|
interoperable with ``Y``.
|
|
|
|
|
|
Remove the private operations section heading and remove::
|
|
|
|
``typename transform_iterator::value_type dereference() const;``
|
|
|
|
:Returns: ``m_f(transform_iterator::dereference());``
|
|
|
|
After the entry for ``functor()``, add::
|
|
|
|
``Iterator const& base() const;``
|
|
|
|
:Returns: ``m_iterator``
|
|
|
|
|
|
``reference operator*() const;``
|
|
|
|
:Returns: ``m_f(*m_iterator)``
|
|
|
|
|
|
``transform_iterator& operator++();``
|
|
|
|
:Effects: ``++m_iterator``
|
|
:Returns: ``*this``
|
|
|
|
|
|
``transform_iterator& operator--();``
|
|
|
|
:Effects: ``--m_iterator``
|
|
:Returns: ``*this``
|
|
|
|
|
|
Change::
|
|
|
|
template <class Predicate, class Iterator>
|
|
class filter_iterator
|
|
: public iterator_adaptor<
|
|
filter_iterator<Predicate, Iterator>, Iterator
|
|
, use_default
|
|
, /* see details */
|
|
>
|
|
{
|
|
public:
|
|
|
|
to::
|
|
|
|
template <class Predicate, class Iterator>
|
|
class filter_iterator
|
|
{
|
|
public:
|
|
typedef iterator_traits<Iterator>::value_type value_type;
|
|
typedef iterator_traits<Iterator>::reference reference;
|
|
typedef iterator_traits<Iterator>::pointer pointer;
|
|
typedef iterator_traits<Iterator>::difference_type difference_type;
|
|
typedef /* see below */ iterator_category;
|
|
|
|
Change::
|
|
|
|
private: // as-if specification
|
|
void increment()
|
|
{
|
|
++(this->base_reference());
|
|
satisfy_predicate();
|
|
}
|
|
|
|
void satisfy_predicate()
|
|
{
|
|
while (this->base() != this->m_end && !this->m_predicate(*this->base()))
|
|
++(this->base_reference());
|
|
}
|
|
|
|
Predicate m_predicate;
|
|
Iterator m_end;
|
|
|
|
to::
|
|
|
|
Iterator const& base() const;
|
|
reference operator*() const;
|
|
filter_iterator& operator++();
|
|
private:
|
|
Predicate m_pred; // exposition only
|
|
Iterator m_iter; // exposition only
|
|
Iterator m_end; // exposition only
|
|
|
|
|
|
|
|
Change:
|
|
The base ``Iterator`` parameter must be a model of Readable
|
|
Iterator and Single Pass Iterator. The resulting
|
|
``filter_iterator`` will be a model of Forward Traversal Iterator
|
|
if ``Iterator`` is, otherwise the ``filter_iterator`` will be a
|
|
model of Single Pass Iterator. The access category of the
|
|
``filter_iterator`` will be the same as the access category of
|
|
``Iterator``.
|
|
|
|
to:
|
|
The ``Iterator`` argument shall meet the requirements of Readable
|
|
Iterator and Single Pass Iterator or it shall meet the requirements of
|
|
Input Iterator.
|
|
|
|
After the requirements section, add:
|
|
|
|
.. topic:: ``filter_iterator`` models
|
|
|
|
The concepts that ``filter_iterator`` models are dependent on which
|
|
concepts the ``Iterator`` argument models, as specified in the
|
|
following tables.
|
|
|
|
+-----------------------------+----------------------------------------------------------+
|
|
| If ``Iterator`` models | then ``filter_iterator`` models |
|
|
+=============================+==========================================================+
|
|
| Single Pass Iterator | Single Pass Iterator |
|
|
+-----------------------------+----------------------------------------------------------+
|
|
| Forward Traversal Iterator | Forward Traversal Iterator |
|
|
+-----------------------------+----------------------------------------------------------+
|
|
|
|
+--------------------------------+----------------------------------------------+
|
|
| If ``Iterator`` models | then ``filter_iterator`` models |
|
|
+================================+==============================================+
|
|
| Readable Iterator | Readable Iterator |
|
|
+--------------------------------+----------------------------------------------+
|
|
| Writable Iterator | Writable Iterator |
|
|
+--------------------------------+----------------------------------------------+
|
|
| Lvalue Iterator | Lvalue Iterator |
|
|
+--------------------------------+----------------------------------------------+
|
|
|
|
+-------------------------------------------------------+---------------------------------+
|
|
| If ``Iterator`` models | then ``filter_iterator`` models |
|
|
+=======================================================+=================================+
|
|
| Readable Iterator, Single Pass Iterator | Input Iterator |
|
|
+-------------------------------------------------------+---------------------------------+
|
|
| Readable Lvalue Iterator, Forward Traversal Iterator | Forward Iterator |
|
|
+-------------------------------------------------------+---------------------------------+
|
|
| Writable Lvalue Iterator, Forward Traversal Iterator | Mutable Forward Iterator |
|
|
+-------------------------------------------------------+---------------------------------+
|
|
|
|
|
|
``filter_iterator<P1, X>`` is interoperable with ``filter_iterator<P2, Y>``
|
|
if and only if ``X`` is interoperable with ``Y``.
|
|
|
|
|
|
Change:
|
|
:Returns: a ``filter_iterator`` whose
|
|
predicate is a default constructed ``Predicate`` and
|
|
whose ``end`` is a default constructed ``Iterator``.
|
|
|
|
to:
|
|
:Effects: Constructs a ``filter_iterator`` whose``m_pred``, ``m_iter``, and ``m_end``
|
|
members are a default constructed.
|
|
|
|
Change:
|
|
:Returns: A ``filter_iterator`` at position ``x`` that filters according
|
|
to predicate ``f`` and that will not increment past ``end``.
|
|
|
|
to:
|
|
:Effects: Constructs a ``filter_iterator`` where ``m_iter`` is either
|
|
the first position in the range ``[x,end)`` such that ``f(*m_iter) == true``
|
|
or else``m_iter == end``. The member ``m_pred`` is constructed from
|
|
``f`` and ``m_end`` from ``end``.
|
|
|
|
Change:
|
|
:Returns: A ``filter_iterator`` at position ``x`` that filters
|
|
according to a default constructed ``Predicate``
|
|
and that will not increment past ``end``.
|
|
|
|
to:
|
|
:Effects: Constructs a ``filter_iterator`` where ``m_iter`` is either
|
|
the first position in the range ``[x,end)`` such that ``m_pred(*m_iter) == true``
|
|
or else``m_iter == end``. The member ``m_pred`` is default constructed.
|
|
|
|
|
|
Change:
|
|
:Returns: A copy of iterator ``t``.
|
|
|
|
to:
|
|
:Effects: Constructs a filter iterator whose members are copied from ``t``.
|
|
|
|
Change:
|
|
:Returns: A copy of the predicate object used to construct ``*this``.
|
|
|
|
to:
|
|
:Returns: ``m_pred``
|
|
|
|
Change:
|
|
:Returns: The object ``end`` used to construct ``*this``.
|
|
|
|
to:
|
|
:Returns: ``m_end``
|
|
|
|
At the end of the operations section, add:
|
|
|
|
``reference operator*() const;``
|
|
|
|
:Returns: ``*m_iter``
|
|
|
|
|
|
``filter_iterator& operator++();``
|
|
|
|
:Effects: Increments ``m_iter`` and then continues to
|
|
increment ``m_iter`` until either ``m_iter == m_end``
|
|
or ``m_pred(*m_iter) == true``.
|
|
:Returns: ``*this``
|
|
|
|
|
|
Change::
|
|
|
|
class counting_iterator
|
|
: public iterator_adaptor<
|
|
counting_iterator<Incrementable, Access, Traversal, Difference>
|
|
, Incrementable
|
|
, Incrementable
|
|
, Access
|
|
, /* see details for traversal category */
|
|
, Incrementable const&
|
|
, Incrementable const*
|
|
, /* distance = Difference or a signed integral type */>
|
|
{
|
|
friend class iterator_core_access;
|
|
public:
|
|
|
|
to::
|
|
|
|
class counting_iterator
|
|
{
|
|
public:
|
|
typedef Incrementable value_type;
|
|
typedef const Incrementable& reference;
|
|
typedef const Incrementable* pointer;
|
|
typedef /* see below */ difference_type;
|
|
typedef /* see below */ iterator_category;
|
|
|
|
|
|
|
|
Change::
|
|
|
|
private:
|
|
typename counting_iterator::reference dereference() const
|
|
{
|
|
return this->base_reference();
|
|
}
|
|
|
|
to::
|
|
|
|
Incrementable const& base() const;
|
|
reference operator*() const;
|
|
counting_iterator& operator++();
|
|
counting_iterator& operator--();
|
|
private:
|
|
Incrementable m_inc; // exposition
|
|
|
|
After the synopsis, add:
|
|
|
|
If the ``Difference`` argument is ``use_default`` then
|
|
``difference_type`` is an unspecified signed integral
|
|
type. Otherwise ``difference_type`` is ``Difference``.
|
|
|
|
``iterator_category`` is determined according to the following
|
|
algorithm:
|
|
|
|
.. parsed-literal::
|
|
|
|
if (CategoryOrTraversal is not use_default)
|
|
return CategoryOrTraversal
|
|
else if (numeric_limits<Incrementable>::is_specialized)
|
|
return |iterator-category|\ (
|
|
random_access_traversal_tag, Incrementable, const Incrementable&)
|
|
else
|
|
return |iterator-category|\ (
|
|
iterator_traversal<Incrementable>::type,
|
|
Incrementable, const Incrementable&)
|
|
|
|
|
|
|
|
Change:
|
|
[*Note:* implementers are encouraged to provide an implementation of
|
|
``distance_to`` and a ``difference_type`` that avoids overflows in
|
|
the cases when the ``Incrementable`` type is a numeric type.]
|
|
|
|
to:
|
|
[*Note:* implementers are encouraged to provide an implementation of
|
|
``operator-`` and a ``difference_type`` that avoid overflows in
|
|
the cases where ``std::numeric_limits<Incrementable>::is_specialized``
|
|
is true.]
|
|
|
|
Change:
|
|
The ``Incrementable`` type must be Default Constructible, Copy
|
|
Constructible, and Assignable. The default distance is
|
|
an implementation defined signed integegral type.
|
|
|
|
The resulting ``counting_iterator`` models Readable Lvalue Iterator.
|
|
|
|
to:
|
|
The ``Incrementable`` argument shall be Copy Constructible and Assignable.
|
|
|
|
Change:
|
|
Furthermore, if you wish to create a counting iterator that is a Forward
|
|
Traversal Iterator, then the following expressions must be valid:
|
|
|
|
to:
|
|
If ``iterator_category`` is convertible to ``forward_iterator_tag``
|
|
or ``forward_traversal_tag``, the following must be well-formed:
|
|
|
|
Change:
|
|
If you wish to create a counting iterator that is a
|
|
Bidirectional Traversal Iterator, then pre-decrement is also required:
|
|
|
|
to:
|
|
If ``iterator_category`` is convertible to
|
|
``bidirectional_iterator_tag`` or ``bidirectional_traversal_tag``,
|
|
the following expression must also be well-formed:
|
|
|
|
Change:
|
|
If you wish to create a counting iterator that is a Random Access
|
|
Traversal Iterator, then these additional expressions are also
|
|
required:
|
|
|
|
to:
|
|
If ``iterator_category`` is convertible to
|
|
``random_access_iterator_tag`` or ``random_access_traversal_tag``,
|
|
the following must must also be valid:
|
|
|
|
After the requirements section, add:
|
|
|
|
.. topic:: ``counting_iterator`` models
|
|
|
|
Specializations of ``counting_iterator`` model Readable Lvalue
|
|
Iterator. In addition, they model the concepts corresponding to the
|
|
iterator tags to which their ``iterator_category`` is convertible.
|
|
Also, if ``CategoryOrTraversal`` is not ``use_default`` then
|
|
``counting_iterator`` models the concept corresponding to the iterator
|
|
tag ``CategoryOrTraversal``. Otherwise, if
|
|
``numeric_limits<Incrementable>::is_specialized``, then
|
|
``counting_iterator`` models Random Access Traversal Iterator.
|
|
Otherwise, ``counting_iterator`` models the same iterator traversal
|
|
concepts modeled by ``Incrementable``.
|
|
|
|
``counting_iterator<X,C1,D1>`` is interoperable with
|
|
``counting_iterator<Y,C2,D2>`` if and only if ``X`` is
|
|
interoperable with ``Y``.
|
|
|
|
At the begining of the operations section, add:
|
|
|
|
In addition to the operations required by the concepts modeled by
|
|
``counting_iterator``, ``counting_iterator`` provides the following
|
|
operations.
|
|
|
|
Change:
|
|
:Returns: A default constructed instance of ``counting_iterator``.
|
|
|
|
to:
|
|
:Requires: ``Incrementable`` is Default Constructible.
|
|
:Effects: Default construct the member ``m_inc``.
|
|
|
|
Change:
|
|
:Returns: An instance of ``counting_iterator`` that is a copy of ``rhs``.
|
|
|
|
to:
|
|
:Effects: Construct member ``m_inc`` from ``rhs.m_inc``.
|
|
|
|
Change:
|
|
:Returns: An instance of ``counting_iterator`` with its base
|
|
object copy constructed from ``x``.
|
|
|
|
to:
|
|
:Effects: Construct member ``m_inc`` from ``x``.
|
|
|
|
At the end of the operations section, add:
|
|
|
|
``reference operator*() const;``
|
|
|
|
:Returns: ``m_inc``
|
|
|
|
|
|
``counting_iterator& operator++();``
|
|
|
|
:Effects: ``++m_inc``
|
|
:Returns: ``*this``
|
|
|
|
|
|
``counting_iterator& operator--();``
|
|
|
|
:Effects: ``--m_inc``
|
|
:Returns: ``*this``
|
|
|
|
|
|
``Incrementable const& base() const;``
|
|
|
|
:Returns: ``m_inc``
|
|
|
|
|
|
9.38x Problem with specification of a->m in Readable Iterator
|
|
=============================================================
|
|
|
|
:Submitter: Howard Hinnant
|
|
:Status: New
|
|
|
|
c++std-lib-12585:
|
|
|
|
Readable Iterator Requirements says:
|
|
|
|
+----------+--------+-----------------------------------------------------------+
|
|
| ``a->m`` | ``U&`` | pre: ``(*a).m`` is well-defined. Equivalent to ``(*a).m`` |
|
|
+----------+--------+-----------------------------------------------------------+
|
|
|
|
Do we mean to outlaw iterators with proxy references from meeting
|
|
the readable requirements?
|
|
|
|
Would it be better for the requirements to read ``static_cast<T>(*a).m``
|
|
instead of ``(*a).m`` ?
|
|
|
|
:Proposed resolution: NAD.
|
|
|
|
:Rationale: We think you're misreading "pre:".
|
|
If ``(*a).m`` is not well defined, then the iterator is not
|
|
required to provide ``a->m``. So a proxy iterator is not
|
|
required to provide ``a->m``.
|
|
|
|
As an aside, it is possible for proxy iterators to
|
|
support ``->``, so changing the requirements to
|
|
read ``static_cast<T>(*a).m`` is interesting.
|
|
However, such a change to Readable Iterator would
|
|
mean that it no longer corresponds to the
|
|
input iterator requirements. So old iterators would not
|
|
necessarily conform to new iterator requirements.
|
|
|
|
|
|
9.39x counting_iterator Traversal argument unspecified
|
|
======================================================
|
|
|
|
:Submitter: Pete Becker
|
|
|
|
c++std-lib-12635:
|
|
|
|
counting_iterator takes an argument for its Traversal type, with a
|
|
default value of use_default. It is derived from an instance of
|
|
iterator_adaptor, where the argument passed for the Traversal type
|
|
is described as "\ ``/* see details for traversal category
|
|
*/``". The details for counting_iterator describe constraints on
|
|
the Incrementable type imposed by various traversal
|
|
categories. There is no description of what the argument to
|
|
iterator_adaptor should be.
|
|
|
|
|
|
:Proposed resolution:
|
|
We no longer inherit from iterator_adaptor. So instead,
|
|
we specify the iterator_category in terms of the Traversal type
|
|
(which is now called CategoryOrTraversal). Also the
|
|
requirements and models section was reorganized to
|
|
match these changes and to make more sense.
|
|
|
|
|
|
|
|
9.40x indirect_iterator requirements muddled
|
|
============================================
|
|
|
|
:Submitter: Pete Becker
|
|
|
|
c++std-lib-12640:
|
|
|
|
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.
|
|
|
|
I'd say this a bit differently, to emphasize what's required:
|
|
iterator_traits<Iterator>::value_type must be dereferenceable.
|
|
The Reference template parameter must be the same type as
|
|
``*iterator_traits<Iterator>::value_type()``.
|
|
|
|
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.
|
|
|
|
Also non-volatile, right? In other words, if Value isn't use_default, it
|
|
just gets passed as the Value argument for iterator_adaptor.
|
|
|
|
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 earlier requirement is that
|
|
``iterator_traits<Iterator>::value_type`` must be
|
|
dereferenceable. Now it's being treated as an iterator. Is this
|
|
just a pun, or is ``iterator_traits<Iterator>::value_type``
|
|
required to be some form of iterator? If it's the former we need
|
|
to find a different way to say it. If it's the latter we need to
|
|
say so.
|
|
|
|
:Proposed resolution:
|
|
Change:
|
|
|
|
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 ``Access`` and ``Traversal`` parameters are passed
|
|
unchanged to the corresponding parameters of the
|
|
``iterator_adaptor`` base class, and the ``Iterator`` parameter
|
|
is passed unchanged as the ``Base`` parameter to the
|
|
``iterator_adaptor`` base class.
|
|
|
|
to:
|
|
|
|
The expression ``*v``, where ``v`` is an object of
|
|
``iterator_traits<Iterator>::value_type``, shall be valid
|
|
expression and convertible to ``reference``. ``Iterator``
|
|
shall model the traversal concept indicated by
|
|
``iterator_category``. ``Value``, ``Reference``, and
|
|
``Difference`` shall be chosen so that ``value_type``,
|
|
``reference``, and ``difference_type`` meet the requirements
|
|
indicated by ``iterator_category``.
|
|
|
|
[Note: there are further requirements on the
|
|
``iterator_traits<Iterator>::value_type`` if the ``Value``
|
|
parameter is not ``use_default``, as implied by the algorithm
|
|
for deducing the default for the ``value_type`` member.]
|
|
|
|
|
|
:Rationale: Not included above is the specification of the
|
|
``value_type``, ``reference``, etc., members, which is handled by
|
|
the changes in 9.37x.
|
|
|
|
|
|
9.41x Problem with transform_iterator requirements
|
|
==================================================
|
|
|
|
:Submitter: Pete Becker
|
|
|
|
c++std-lib-12641:
|
|
|
|
The reference type of transform_iterator is ``result_of<
|
|
UnaryFunction(iterator_traits<Iterator>::reference)
|
|
>::type``. The ``value_type`` is
|
|
``remove_cv<remove_reference<reference> >::type``.
|
|
|
|
These are the defaults, right? If the user supplies their own types
|
|
that's what gets passed to iterator_adaptor. And again, the
|
|
specification should be in terms of the specialization of
|
|
iterator_adaptor, and not in terms of the result:
|
|
|
|
Reference argument to iterator_adaptor::
|
|
|
|
if (Reference != use_default)
|
|
Reference
|
|
else
|
|
result_of<
|
|
UnaryFunction(iterator_traits<Iterator>::reference)
|
|
>::type
|
|
|
|
Value argument to iterator_adaptor::
|
|
|
|
if (Value != use_default)
|
|
Value
|
|
else if (Reference != use_default)
|
|
remove_reference<reference>::type
|
|
else
|
|
remove_reference<
|
|
result_of<
|
|
UnaryFunction(iterator_traits<Iterator>::reference)
|
|
>::type
|
|
>::type
|
|
|
|
There's probably a better way to specify that last alternative, but
|
|
I've been at this too long, and it's all turning into a maze of
|
|
twisty passages, all alike.
|
|
|
|
:Proposed resolution:
|
|
Replace:
|
|
|
|
The reference type of transform_iterator is ``result_of<
|
|
UnaryFunction(iterator_traits<Iterator>::reference)
|
|
>::type``. The ``value_type`` is
|
|
``remove_cv<remove_reference<reference> >::type``.
|
|
|
|
with:
|
|
|
|
If ``Reference`` is ``use_default`` then the ``reference``
|
|
member of ``transform_iterator`` is ``result_of<
|
|
UnaryFunction(iterator_traits<Iterator>::reference)
|
|
>::type``. Otherwise, ``reference`` is ``Reference``.
|
|
|
|
If ``Value`` is ``use_default`` then the ``value_type``
|
|
member is ``remove_cv<remove_reference<reference> >::type``.
|
|
Otherwise, ``value_type`` is ``Value``.
|
|
|
|
|
|
9.42x filter_iterator details unspecified
|
|
=========================================
|
|
|
|
:Submitter: Pete Becker
|
|
|
|
c++std-lib-12642:
|
|
|
|
The paper says::
|
|
|
|
template<class Predicate, class Iterator>
|
|
class filter_iterator
|
|
: public iterator_adaptor<
|
|
filter_iterator<Predicate, Iterator>,
|
|
Iterator,
|
|
use_default,
|
|
/* see details */ >
|
|
|
|
That comment covers the Access, Traversal, Reference, and Difference
|
|
arguments. The only specification for any of these in the details is:
|
|
|
|
The access category of the filter_iterator will be the same as
|
|
the access category of Iterator.
|
|
|
|
Needs more.
|
|
|
|
:Proposed resolution:
|
|
Add to the synopsis::
|
|
|
|
typedef iterator_traits<Iterator>::value_type value_type;
|
|
typedef iterator_traits<Iterator>::reference reference;
|
|
typedef iterator_traits<Iterator>::pointer pointer;
|
|
typedef iterator_traits<Iterator>::difference_type difference_type;
|
|
typedef /* see below */ iterator_category;
|
|
|
|
and add just after the synopsis:
|
|
|
|
If ``Iterator`` models Readable Lvalue Iterator and Forward
|
|
Traversal Iterator then ``iterator_category`` is convertible
|
|
to ``std::forward_iterator_tag``. Otherwise
|
|
``iterator_category`` is convertible to
|
|
``std::input_iterator_tag``.
|
|
|
|
|
|
9.43x transform_iterator interoperability too restrictive
|
|
=========================================================
|
|
|
|
:Submitter: Jeremy Siek
|
|
|
|
We do not need to require that the function objects have the same
|
|
type, just that they be convertible.
|
|
|
|
:Proposed resolution:
|
|
|
|
Change::
|
|
|
|
template<class OtherIterator, class R2, class V2>
|
|
transform_iterator(
|
|
transform_iterator<UnaryFunction, OtherIterator, R2, V2> const& t
|
|
, typename enable_if_convertible<OtherIterator, Iterator>::type* = 0 // exposition
|
|
);
|
|
|
|
to::
|
|
|
|
template<class F2, class I2, class R2, class V2>
|
|
transform_iterator(
|
|
transform_iterator<F2, I2, R2, V2> const& t
|
|
, typename enable_if_convertible<I2, Iterator>::type* = 0 // exposition only
|
|
, typename enable_if_convertible<F2, UnaryFunction>::type* = 0 // exposition only
|
|
);
|
|
|
|
|
|
9.44y ``indirect_iterator`` and smart pointers
|
|
==============================================
|
|
|
|
:Submitter: Dave Abrahams
|
|
|
|
``indirect_iterator`` should be able to iterate over containers of
|
|
smart pointers, but the mechanism that allows it was left out of
|
|
the specification, even though it's present in the Boost
|
|
specification
|
|
|
|
:Proposed resolution: Add ``pointee`` and ``indirect_reference``
|
|
to deal with this capability.
|
|
|
|
In [lib.iterator.helper.synopsis], add::
|
|
|
|
template <class Dereferenceable>
|
|
struct pointee;
|
|
|
|
template <class Dereferenceable>
|
|
struct indirect_reference;
|
|
|
|
After ``indirect_iterator``\ 's abstract, add:
|
|
|
|
.. topic:: Class template ``pointee``
|
|
|
|
.. include:: pointee_ref.rst
|
|
|
|
.. topic:: Class template ``indirect_reference``
|
|
|
|
.. include:: indirect_reference_ref.rst
|
|
|
|
See proposed resolution to Issue 9.37x for more changes related to
|
|
this issue.
|
|
|
|
9.45y N1530: Typos and editorial changes in proposal text (not standardese)
|
|
===========================================================================
|
|
|
|
:Submitter: Dave Abrahams
|
|
|
|
1. "because specification helps to highlight that the ``Reference``
|
|
template parameter may not always be identical to the iterator's
|
|
``reference`` type, and will keep users making mistakes based on
|
|
that assumption."
|
|
|
|
:Proposed resolution: add "from" before "making"
|
|
|
|
2. mention of obsolete projection_iterator
|
|
|
|
:Proposed Resolution:
|
|
|
|
From n1530, in the **Specialized Adaptors** section, remove:
|
|
|
|
``projection_iterator``, which is similar to ``transform_iterator``
|
|
except that when dereferenced it returns a reference instead of
|
|
a value.
|
|
|
|
:Rationale:
|
|
This iterator was in the original boost library, but the new
|
|
iterator concepts allowed this iterator to be
|
|
folded into ``transform_iterator``.
|
|
|
|
|
|
|
|
9.46y N1530: ``base()`` return-by-value is costly
|
|
=================================================
|
|
|
|
:Submitter: Dave Abrahams
|
|
|
|
We've had some real-life reports that iterators that use
|
|
``iterator_adaptor``\ 's ``base()`` function can be inefficient
|
|
when the ``Base`` iterator is expensive to copy. Iterators, of
|
|
all things, should be efficient.
|
|
|
|
:Proposed resolution:
|
|
|
|
In [lib.iterator.adaptor]
|
|
|
|
Change::
|
|
|
|
Base base() const;
|
|
|
|
to::
|
|
|
|
Base const& base() const;
|
|
|
|
twice (once in the synopsis and once in the **public
|
|
operations** section).
|
|
|
|
|
|
9.47x Forgot default constructible in Forward Traversal Iterator
|
|
================================================================
|
|
|
|
:Submitter: Jeremy Siek
|
|
|
|
We want Forward Traversal Iterator plus Readable Lvalue Iterator to
|
|
match the old Foward Iterator requirements, so we need Forward
|
|
Traversal Iterator to include Default Constructible.
|
|
|
|
:Proposed resolution:
|
|
|
|
Change:
|
|
|
|
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) |
|
|
+---------------------------------------+-----------------------------------+---------------+
|
|
|
|
to:
|
|
|
|
A class or built-in type ``X`` models the *Forward Traversal Iterator*
|
|
concept if, in addition to ``X`` meeting the requirements of
|
|
Default Constructible and Single Pass Iterator, the following
|
|
expressions are valid and respect the
|
|
stated semantics.
|
|
|
|
+--------------------------------------------------------------------------------------------------------+
|
|
|Forward Traversal Iterator Requirements (in addition to Default Constructible and Single Pass Iterator) |
|
|
+---------------------------------------+-----------------------------------+----------------------------+
|
|
|
|
9.48x Editorial changes (non-normative text)
|
|
============================================
|
|
|
|
Change:
|
|
Iterator facade uses the Curiously Recurring Template Pattern (CRTP)
|
|
[Cop95] so that the user can specify the behavior of
|
|
``iterator_facade`` in a derived class. Former designs used policy
|
|
objects to specify the behavior. ``iterator_facade`` does not use policy
|
|
objects for several reasons:
|
|
|
|
to:
|
|
Iterator facade uses the Curiously Recurring Template
|
|
Pattern (CRTP) [Cop95] so that the user can specify the behavior
|
|
of ``iterator_facade`` in a derived class. Former designs used
|
|
policy objects to specify the behavior, but that approach was
|
|
discarded for several reasons:
|
|
|
|
|
|
Change:
|
|
iterator's ``operator++`` returns the iterator type itself means
|
|
that all iterators generated by ``iterator_facade`` would be
|
|
instantiations of ``iterator_facade``. Cumbersome type generator
|
|
|
|
to:
|
|
iterator's ``operator++`` returns the iterator type itself
|
|
would mean that all iterators built with the library would
|
|
have to be specializations of ``iterator_facade<...>``, rather
|
|
than something more descriptive like
|
|
``indirect_iterator<T*>``. Cumbersome type generator
|
|
|
|
|
|
Change:
|
|
The return type for ``operator->`` and ``operator[]`` is not
|
|
explicitly specified. Instead it requires each ``iterator_facade``
|
|
instantiation to meet the requirements of its ``iterator_category``.
|
|
|
|
To:
|
|
The return types for ``iterator_facade``\ 's ``operator->`` and
|
|
``operator[]`` are not explicitly specified. Instead, those types
|
|
are described in terms of a set of requirements, which must be
|
|
satisfied by the ``iterator_facade`` implementation.
|
|
|
|
|
|
9.49x Clarification of iterator_facade requirements and type members
|
|
====================================================================
|
|
|
|
A general cleanup and simplification of the requirements and
|
|
description of type members for ``iterator_facade``.
|
|
|
|
|
|
The user is only allowed to add ``const`` as a qualifier.
|
|
|
|
Change:
|
|
``typedef remove_cv<Value>::type value_type;``
|
|
|
|
to:
|
|
``typedef remove_const<Value>::type value_type;``
|
|
|
|
|
|
We use to have an unspecified type for ``pointer``, to match the
|
|
return type of ``operator->``, but there's no real reason to make them
|
|
match, so we just use the simpler ``Value*`` for ``pointer``.
|
|
|
|
Change:
|
|
|
|
``typedef /* see description of operator-> */ pointer;``
|
|
|
|
To:
|
|
``typedef Value* pointer;``
|
|
|
|
|
|
Remove:
|
|
Some of the constraints on template parameters to
|
|
``iterator_facade`` are expressed in terms of resulting nested
|
|
types and should be viewed in the context of their impact on
|
|
``iterator_traits<Derived>``.
|
|
|
|
Change:
|
|
The ``Derived`` template parameter must be a class derived from
|
|
``iterator_facade``.
|
|
|
|
and:
|
|
The following table describes the other requirements on the
|
|
``Derived`` parameter. Depending on the resulting iterator's
|
|
``iterator_category``, a subset of the expressions listed in the table
|
|
are required to be valid. The operations in the first column must be
|
|
accessible to member functions of class ``iterator_core_access``.
|
|
|
|
to:
|
|
The following table describes the typical valid expressions on
|
|
``iterator_facade``\ 's ``Derived`` parameter, depending on the
|
|
iterator concept(s) it will model. The operations in the first
|
|
column must be made accessible to member functions of class
|
|
``iterator_core_access``. In addition,
|
|
``static_cast<Derived*>(iterator_facade*)`` shall be well-formed.
|
|
|
|
|
|
Remove:
|
|
The nested ``::value_type`` type will be the same as
|
|
``remove_cv<Value>::type``, so the ``Value`` parameter must be
|
|
an (optionally ``const``\ -qualified) non-reference type.
|
|
|
|
The nested ``::reference`` will be the same as the ``Reference``
|
|
parameter; it must be a suitable reference type for the resulting
|
|
iterator. The default for the ``Reference`` parameter is
|
|
``Value&``.
|
|
|
|
|
|
Change:
|
|
|
|
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 |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 |Single Pass Iterator |
|
|
| | |equivalent. | |
|
|
+--------------------+-------------------+-------------------------------------+---------------------------+
|
|
|``c.equal(y)`` |convertible to bool|true iff ``c`` and ``y`` refer to the|Single Pass Iterator |
|
|
| | |same 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 |equivalent to ``distance(c, b)`` |Random Access Traversal |
|
|
| |X::difference_type | |Iterator |
|
|
+--------------------+-------------------+-------------------------------------+---------------------------+
|
|
|``c.distance_to(z)``|convertible to |equivalent to ``distance(c, z)``. |Random Access Traversal |
|
|
| |X::difference_type |Implements ``c - z``, ``c < z``, ``c |Iterator |
|
|
| | |<= z``, ``c > z``, and ``c >= c``. | |
|
|
+--------------------+-------------------+-------------------------------------+---------------------------+
|
|
|
|
to:
|
|
|
|
In the table below, ``F`` is ``iterator_facade<X,V,C,R,D>``, ``a`` is an
|
|
object of type ``X``, ``b`` and ``c`` are objects of type ``const X``,
|
|
``n`` is an object of ``F::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``.
|
|
|
|
**iterator_facade Core Operations**
|
|
|
|
+--------------------+----------------------+-------------------------+---------------------------+
|
|
|Expression |Return Type |Assertion/Note |Used to implement Iterator |
|
|
| | | |Concept(s) |
|
|
+====================+======================+=========================+===========================+
|
|
|``c.dereference()`` |``F::reference`` | |Readable Iterator, Writable|
|
|
| | | |Iterator |
|
|
+--------------------+----------------------+-------------------------+---------------------------+
|
|
|``c.equal(y)`` |convertible to bool |true iff ``c`` and ``y`` |Single Pass Iterator |
|
|
| | |refer to the same | |
|
|
| | |position. | |
|
|
+--------------------+----------------------+-------------------------+---------------------------+
|
|
|``a.increment()`` |unused | |Incrementable Iterator |
|
|
+--------------------+----------------------+-------------------------+---------------------------+
|
|
|``a.decrement()`` |unused | |Bidirectional Traversal |
|
|
| | | |Iterator |
|
|
+--------------------+----------------------+-------------------------+---------------------------+
|
|
|``a.advance(n)`` |unused | |Random Access Traversal |
|
|
| | | |Iterator |
|
|
+--------------------+----------------------+-------------------------+---------------------------+
|
|
|``c.distance_to(z)``|convertible to |equivalent to |Random Access Traversal |
|
|
| |``F::difference_type``|``distance(c, X(z))``. |Iterator |
|
|
+--------------------+----------------------+-------------------------+---------------------------+
|
|
|
|
|
|
|