Edits for clarity and correctness.

[SVN r20831]
This commit is contained in:
Dave Abrahams
2003-11-17 17:15:26 +00:00
parent 104faa5ab3
commit f25ff7a1a4
2 changed files with 241 additions and 334 deletions

View File

@ -23,17 +23,18 @@
==============
The ``is_writable`` and ``is_swappable`` traits classes in N1550_
provide a mechanism for determining at compile time if a type is a
model of the new Writable Iterator and Swappable Iterator concepts,
analogous to ``iterator_traits<X>::iterator_category`` for the old
iterator concepts. For backward compatibility, ``is_writable`` and
``is_swappable`` not only work with new iterators, but they also are
intended to work for old iterators (iterators that meet the
requirements for one of the iterator concepts in the current
standard). In the case of old iterators, the writability and
swapability is deduced based on the ``iterator_category`` and also the
``reference`` type. The specification for this deduction gives false
positives for forward iterators that have non-assignable value types.
provide a mechanism for determining at compile time if an iterator
type is a model of the new Writable Iterator and Swappable Iterator
concepts, analogous to ``iterator_traits<X>::iterator_category``
for the old iterator concepts. For backward compatibility,
``is_writable`` and ``is_swappable`` not only work with new
iterators, but they also are intended to work for old
iterators (iterators that meet the requirements for one of the
iterator concepts in the current standard). In the case of old
iterators, the writability and swapability is deduced based on the
``iterator_category`` and also the ``reference`` type. The
specification for this deduction gives false positives for forward
iterators that have non-assignable value types.
To review, the part of the ``is_writable`` trait definition which
applies to old iterators is::
@ -47,8 +48,8 @@ applies to old iterators is::
else
return false;
Suppose the ``value_type`` of the iterator has a private assignment
operator::
Suppose the ``value_type`` of the iterator ``It`` has a private
assignment operator::
class B {
public:
@ -57,9 +58,9 @@ operator::
B& operator=(const B&);
};
and suppose the ``reference`` type of the iterator is ``B&``. Then
``is_writable`` will deduce true when in fact attempting to write into
``B`` will cause an error.
and suppose the ``reference`` type of the iterator is ``B&``. In
that case, ``is_writable<It>::value`` will be true when in fact
attempting to write into ``B`` will cause an error.
The same problem applies to ``is_swappable``.
@ -81,64 +82,78 @@ The same problem applies to ``is_swappable``.
Remove the requirement for support of the ``is_readable`` trait from
the Readable Iterator concept.
.. We should give some attention to the UnaryTypeTrait concept,
which requires the trait to be derived from either true_type or
false_type (as of the last LWG meeting).
3. Change ``iterator_tag`` to::
template <class Value, class Reference, class Traversal>
struct iterator_tag;
The argument for ``Value`` must be the value type of the
iterator, ``Reference`` must be the return type of
``operator*`` [*]_, and ``Traversal`` the traversal tag for the
iterator.
The argument for ``Value`` must be the ``value_type`` of the
iterator, possibly const-qualified, ``Reference`` must be the
return type of ``operator*`` [*]_, and ``Traversal`` the
traversal tag for the iterator.
``iterator_tag`` is required to be convertible to both the
``Traversal`` tag and also to the appropriate old iterator category
tag, as specified by the following pseudo-code::
.. I think the language above is still too informal. There is no
"the iterator", when considering iterator_tag in isolation.
Perhaps that language belongs in a non-normative note
inherit-category(Value, Reference, Traversal) =
``iterator_tag<Value,Reference,Traversal>`` is required to be
convertible to both ``Traversal`` tag and also to the
``iterator_category`` type specified by the following
pseudo-code::
old-category(Value, Reference, Traversal) =
if (Reference is a reference
and Traversal is convertible to forward_traversal_tag) {
and Traversal is convertible to forward_traversal_tag)
{
if (Traversal is convertible to random_access_traversal_tag)
return random_access_iterator_tag;
else if (Traversal is convertible to bidirectional_traversal_tag)
return bidirectional_iterator_tag;
else
return forward_iterator_tag;
} else if (Traversal is convertible to single_pass_traversal_tag
and Reference is convertible to Value) {
}
else if (Traversal is convertible to single_pass_traversal_tag
and Reference is convertible to Value)
{
if (Value is const)
return input_iterator_tag;
else
return input_output_iterator_tag;
} else
return output_iterator_tag;
.. I reformatted the code for legibility; sorry.
.. [*] Instead of saying "return type of operator*", we could have
said ``iterator_traits<X>::reference``. However, the standard
specifies nothing about ``iterator_traits<X>::reference``,
which we believe is a defect. Once the defect is fixed,
the above could be rephrased.
specifies nothing about ``iterator_traits<X>::reference`` in
many cases, which we believe is a defect. Furthermore, in some
cases it explicitly differs from the return type of
``operator*``, for example see ``istreambuf_iterator``.
4. Change the specification of ``traversal_category`` to::
traversal-category(Iterator) =
let cat = iterator_traits<Iterator>::iterator_category
if (cat convertible to incrementable_iterator_tag)
return cat; // Iterator is a new iterator
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;
let cat = iterator_traits<Iterator>::iterator_category
if (cat is convertible to incrementable_iterator_tag)
return cat; // Iterator is a new iterator
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;
==========
@ -150,7 +165,7 @@ The same problem applies to ``is_swappable``.
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
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
@ -160,12 +175,11 @@ The same problem applies to ``is_swappable``.
that need these capabilities have no alternative if
they are not provided.
2. We discovered that the ``is_readable`` trait can be
implemented without special hints from the iterator.
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.
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. With ``is_writable`` and ``is_swappable`` gone, and
``is_readable`` no longer in need of special hints,
@ -181,7 +195,7 @@ The same problem applies to ``is_swappable``.
deduce the appropriate old iterator category. The
``Value`` and ``Reference`` parameters fill this need.
Note that this solution cleans up the issue that John
Maddock raised on the reflector about the non-uniformity
Maddock raised on the reflector (``c++std-lib-12187``) about the non-uniformity
of the lvalue bit.
4. The changes to the specification of ``traversal_category`` are a