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

@ -4,7 +4,7 @@
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.3.1: http://docutils.sourceforge.net/" /> <meta name="generator" content="Docutils 0.3.1: http://docutils.sourceforge.net/" />
<title>Issues With N1550 and N1530</title> <title>Problem with is_writable and is_swappable in N1550</title>
<style type="text/css"><!-- <style type="text/css"><!--
/* /*
@ -199,21 +199,21 @@ ul.auto-toc {
--></style> --></style>
</head> </head>
<body> <body>
<div class="document" id="issues-with-n1550-and-n1530"> <div class="document" id="problem-with-is-writable-and-is-swappable-in-n1550">
<h1 class="title">Issues With <a class="reference" href="http://www.boost-consulting.com/writing/n1550.html">N1550</a> and <a class="reference" href="http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1530.html">N1530</a></h1> <h1 class="title">Problem with <tt class="literal"><span class="pre">is_writable</span></tt> and <tt class="literal"><span class="pre">is_swappable</span></tt> in <a class="reference" href="http://www.boost-consulting.com/writing/n1550.html">N1550</a></h1>
<table class="field-list" frame="void" rules="none"> <table class="field-list" frame="void" rules="none">
<col class="field-name" /> <col class="field-name" />
<col class="field-body" /> <col class="field-body" />
<tbody valign="top"> <tbody valign="top">
<tr class="field"><th class="field-name">Author:</th><td class="field-body">David Abrahams</td> <tr class="field"><th class="field-name">Author:</th><td class="field-body">David Abrahams and Jeremy Siek</td>
</tr> </tr>
<tr class="field"><th class="field-name">Contact:</th><td class="field-body"><a class="reference" href="mailto:dave&#64;boost-consulting.com">dave&#64;boost-consulting.com</a></td> <tr class="field"><th class="field-name">Contact:</th><td class="field-body"><a class="reference" href="mailto:dave&#64;boost-consulting.com">dave&#64;boost-consulting.com</a>, <a class="reference" href="mailto:jsiek&#64;osl.iu.edu">jsiek&#64;osl.iu.edu</a></td>
</tr> </tr>
<tr class="field"><th class="field-name">Organization:</th><td class="field-body"><a class="reference" href="http://www.boost-consulting.com">Boost Consulting</a></td> <tr class="field"><th class="field-name">Organization:</th><td class="field-body"><a class="reference" href="http://www.boost-consulting.com">Boost Consulting</a>, Indiana University Bloomington</td>
</tr> </tr>
<tr class="field"><th class="field-name">date:</th><td class="field-body">$Date$</td> <tr class="field"><th class="field-name">date:</th><td class="field-body">$Date$</td>
</tr> </tr>
<tr class="field"><th class="field-name">Copyright:</th><td class="field-body">Copyright David Abrahams 2003. Use, modification and <tr class="field"><th class="field-name">Copyright:</th><td class="field-body">Copyright David Abrahams, Jeremy Siek 2003. Use, modification and
distribution is subject to the Boost Software License, distribution is subject to the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt or copy Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
at <a class="reference" href="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</a>)</td> at <a class="reference" href="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</a>)</td>
@ -224,301 +224,194 @@ at <a class="reference" href="http://www.boost.org/LICENSE_1_0.txt">http://www.b
<p class="topic-title"><a name="table-of-contents">Table of Contents</a></p> <p class="topic-title"><a name="table-of-contents">Table of Contents</a></p>
<ul class="simple"> <ul class="simple">
<li><a class="reference" href="#introduction" id="id3" name="id3">Introduction</a></li> <li><a class="reference" href="#introduction" id="id3" name="id3">Introduction</a></li>
<li><a class="reference" href="#the-issues" id="id4" name="id4">The Issues</a><ul> <li><a class="reference" href="#proposed-resolution" id="id4" name="id4">Proposed Resolution</a></li>
<li><a class="reference" href="#non-uniformity-of-the-lvalue-iterator-bit" id="id5" name="id5">Non-Uniformity of the &quot;<tt class="literal"><span class="pre">lvalue_iterator</span></tt> Bit&quot;</a></li> <li><a class="reference" href="#rationale" id="id5" name="id5">Rationale</a></li>
<li><a class="reference" href="#redundancy-of-some-explicit-access-category-flags" id="id6" name="id6">Redundancy of Some Explicit Access Category Flags</a></li>
<li><a class="reference" href="#new-access-traits-templates-wrong-for-some-iterators" id="id7" name="id7">New Access Traits Templates Wrong For Some Iterators</a><ul>
<li><a class="reference" href="#is-writable-iterator" id="id8" name="id8"><tt class="literal"><span class="pre">is_writable_iterator</span></tt></a></li>
<li><a class="reference" href="#is-swappable-iterator" id="id9" name="id9"><tt class="literal"><span class="pre">is_swappable_iterator</span></tt></a></li>
</ul>
</li>
<li><a class="reference" href="#no-use-cases-for-some-access-traits" id="id10" name="id10">No Use Cases for Some Access Traits</a><ul>
<li><a class="reference" href="#id1" id="id11" name="id11"><tt class="literal"><span class="pre">is_swappable_iterator</span></tt></a></li>
<li><a class="reference" href="#id2" id="id12" name="id12"><tt class="literal"><span class="pre">is_writable_iterator</span></tt></a></li>
</ul>
</li>
<li><a class="reference" href="#naming-issues" id="id13" name="id13">Naming Issues</a><ul>
<li><a class="reference" href="#traversal-concepts-and-tags" id="id14" name="id14">Traversal Concepts and Tags</a></li>
<li><a class="reference" href="#access-traits" id="id15" name="id15">Access Traits</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference" href="#proposed-solution-in-progress" id="id16" name="id16">Proposed Solution (in progress)</a><ul>
<li><a class="reference" href="#overview" id="id17" name="id17">Overview</a></li>
<li><a class="reference" href="#future-enhancements" id="id18" name="id18">Future Enhancements</a></li>
<li><a class="reference" href="#impact-on-n1530-iterator-facade-and-adaptor" id="id19" name="id19">Impact on N1530 (Iterator Facade and Adaptor)</a></li>
</ul>
</li>
</ul> </ul>
</div> </div>
<div class="section" id="introduction"> <div class="section" id="introduction">
<h1><a class="toc-backref" href="#id3" name="introduction">Introduction</a></h1> <h1><a class="toc-backref" href="#id3" name="introduction">Introduction</a></h1>
<p>Several issues with <a class="reference" href="http://www.boost-consulting.com/writing/n1550.html">N1550</a> (New Iterator Concepts) were raised in <p>The <tt class="literal"><span class="pre">is_writable</span></tt> and <tt class="literal"><span class="pre">is_swappable</span></tt> traits classes in <a class="reference" href="http://www.boost-consulting.com/writing/n1550.html">N1550</a>
the run-up before the fall 2003 C++ Committee meeting, in a thread provide a mechanism for determining at compile time if an iterator
beginning with John Maddock's posting <tt class="literal"><span class="pre">c++std-lib-12187</span></tt>. In type is a model of the new Writable Iterator and Swappable Iterator
looking at those issues, several other problems came up. This concepts, analogous to <tt class="literal"><span class="pre">iterator_traits&lt;X&gt;::iterator_category</span></tt>
document addresses those issues and discusses some potential for the old iterator concepts. For backward compatibility,
solutions and their impact on <a class="reference" href="http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1530.html">N1530</a> (Iterator Facade and Adaptor).</p> <tt class="literal"><span class="pre">is_writable</span></tt> and <tt class="literal"><span class="pre">is_swappable</span></tt> not only work with new
</div> iterators, but they also are intended to work for old
<div class="section" id="the-issues"> iterators (iterators that meet the requirements for one of the
<h1><a class="toc-backref" href="#id4" name="the-issues">The Issues</a></h1> iterator concepts in the current standard). In the case of old
<div class="section" id="non-uniformity-of-the-lvalue-iterator-bit"> iterators, the writability and swapability is deduced based on the
<h2><a class="toc-backref" href="#id5" name="non-uniformity-of-the-lvalue-iterator-bit">Non-Uniformity of the &quot;<tt class="literal"><span class="pre">lvalue_iterator</span></tt> Bit&quot;</a></h2> <tt class="literal"><span class="pre">iterator_category</span></tt> and also the <tt class="literal"><span class="pre">reference</span></tt> type. The
<p>The proposed <tt class="literal"><span class="pre">iterator_tag</span></tt> class template accepts an &quot;access specification for this deduction gives false positives for forward
bits&quot; parameter which includes a bit to indicate the iterator's iterators that have non-assignable value types.</p>
<em>lvalueness</em> (whether its dereference operator returns a reference <p>To review, the part of the <tt class="literal"><span class="pre">is_writable</span></tt> trait definition which
to its <tt class="literal"><span class="pre">value_type</span></tt>. The relevant part of <a class="reference" href="http://www.boost-consulting.com/writing/n1550.html">N1550</a> says:</p> applies to old iterators is:</p>
<blockquote>
The purpose of the <tt class="literal"><span class="pre">lvalue_iterator</span></tt> part of the
<tt class="literal"><span class="pre">iterator_access</span></tt> enum is to communicate to <tt class="literal"><span class="pre">iterator_tag</span></tt>
whether the reference type is an lvalue so that the appropriate
old category can be chosen for the base class. The
<tt class="literal"><span class="pre">lvalue_iterator</span></tt> bit is not recorded in the
<tt class="literal"><span class="pre">iterator_tag::access</span></tt> data member.</blockquote>
<p>The <tt class="literal"><span class="pre">lvalue_iterator</span></tt> bit is not recorded because <a class="reference" href="http://www.boost-consulting.com/writing/n1550.html">N1550</a> aims to
improve orthogonality of the iterator concepts, and a new-style
iterator's lvalueness is detectable by examining its <tt class="literal"><span class="pre">reference</span></tt>
type. This inside/outside difference is awkward and confusing.</p>
</div>
<div class="section" id="redundancy-of-some-explicit-access-category-flags">
<h2><a class="toc-backref" href="#id6" name="redundancy-of-some-explicit-access-category-flags">Redundancy of Some Explicit Access Category Flags</a></h2>
<p>Shortly after <a class="reference" href="http://www.boost-consulting.com/writing/n1550.html">N1550</a> was accepted, we discovered that an iterator's
lvalueness can be determined knowing only its <tt class="literal"><span class="pre">value_type</span></tt>. This
predicate can be calculated even for old-style iterators (on whose
<tt class="literal"><span class="pre">reference</span></tt> 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 <tt class="literal"><span class="pre">T&amp;</span></tt> function template
parameter. Similarly, it is possible to detect an iterator's
readability knowing only its <tt class="literal"><span class="pre">value_type</span></tt>. Thus, any interface
which asks the <em>user</em> to explicitly describe an iterator's
lvalue-ness or readability seems to introduce needless complexity.</p>
</div>
<div class="section" id="new-access-traits-templates-wrong-for-some-iterators">
<h2><a class="toc-backref" href="#id7" name="new-access-traits-templates-wrong-for-some-iterators">New Access Traits Templates Wrong For Some Iterators</a></h2>
<div class="section" id="is-writable-iterator">
<h3><a class="toc-backref" href="#id8" name="is-writable-iterator"><tt class="literal"><span class="pre">is_writable_iterator</span></tt></a></h3>
<p>The part of the <tt class="literal"><span class="pre">is_writable_iterator</span></tt> trait definition which
applies to old-style iterators is:</p>
<pre class="literal-block"> <pre class="literal-block">
if (cat is convertible to output_iterator_tag) if (cat is convertible to output_iterator_tag)
return true; return true;
else if ( else if (cat is convertible to forward_iterator_tag
cat is convertible to forward_iterator_tag
and iterator_traits&lt;Iterator&gt;::reference is a and iterator_traits&lt;Iterator&gt;::reference is a
mutable reference) mutable reference)
return true; return true;
else else
return false;
</pre>
<p>The current forward iterator requirements place no constraints on
the iterator's <tt class="literal"><span class="pre">reference</span></tt> type, so the logic above will give
false negatives for some otherwise-writable forward iterators whose
<tt class="literal"><span class="pre">reference</span></tt> type is not a mutable reference. Also, it will
report false positives for any forward, bidirectional, or random
access iterator whose <tt class="literal"><span class="pre">reference</span></tt> is a mutable reference but
whose <tt class="literal"><span class="pre">value_type</span></tt> is not assignable (e.g. has a private
assignment operator).</p>
</div>
<div class="section" id="is-swappable-iterator">
<h3><a class="toc-backref" href="#id9" name="is-swappable-iterator"><tt class="literal"><span class="pre">is_swappable_iterator</span></tt></a></h3>
<p>Similarly, the part of <tt class="literal"><span class="pre">is_swappable_iterator</span></tt> which applies to
old-style iterators is:</p>
<pre class="literal-block">
else if (cat is convertible to forward_iterator_tag) {
if (iterator_traits&lt;Iterator&gt;::reference is a const reference)
return false;
else
return true;
} else
return false; return false;
</pre> </pre>
<p>In this case false positives are possible for non-writable forward <p>Suppose the <tt class="literal"><span class="pre">value_type</span></tt> of the iterator <tt class="literal"><span class="pre">It</span></tt> has a private
iterators whose <tt class="literal"><span class="pre">reference</span></tt> type is not a reference, or as above, assignment operator:</p>
any forward, bidirectional, or random access iterator whose <pre class="literal-block">
<tt class="literal"><span class="pre">reference</span></tt> is not a constant reference but whose <tt class="literal"><span class="pre">value_type</span></tt> class B {
is not assignable (e.g., because it has a private assignment public:
operator).</p> ...
<p>False negatives can be &quot;reasoned away&quot;: since it is part of a private:
writable iterator's concept definition that B&amp; operator=(const B&amp;);
<tt class="literal"><span class="pre">is_writable&lt;I&gt;::value</span></tt> is <tt class="literal"><span class="pre">true</span></tt>, any iterator for which };
it is <tt class="literal"><span class="pre">false</span></tt> is by definition not writable. This seems like a </pre>
perverse use of logic, though.</p> <p>and suppose the <tt class="literal"><span class="pre">reference</span></tt> type of the iterator is <tt class="literal"><span class="pre">B&amp;</span></tt>. In
<p>It might be reasonable to conclude that it is a defect that the that case, <tt class="literal"><span class="pre">is_writable&lt;It&gt;::value</span></tt> will be true when in fact
standard allows forward iterators with a <tt class="literal"><span class="pre">reference</span></tt> type other attempting to write into <tt class="literal"><span class="pre">B</span></tt> will cause an error.</p>
than <tt class="literal"><span class="pre">value_type</span></tt> <em>cv</em><tt class="literal"><span class="pre">&amp;</span></tt>, but that still leaves the problem <p>The same problem applies to <tt class="literal"><span class="pre">is_swappable</span></tt>.</p>
of old-style iterators whose <tt class="literal"><span class="pre">value_type</span></tt> is not assignable. It
is not possible to correctly compute writability and swappability
for those old-style iterators without intervention
(specializations of <tt class="literal"><span class="pre">is_writable_iterator</span></tt> and
<tt class="literal"><span class="pre">is_swappable_iterator</span></tt>) from a user.</p>
</div> </div>
</div> <div class="section" id="proposed-resolution">
<div class="section" id="no-use-cases-for-some-access-traits"> <h1><a class="toc-backref" href="#id4" name="proposed-resolution">Proposed Resolution</a></h1>
<h2><a class="toc-backref" href="#id10" name="no-use-cases-for-some-access-traits">No Use Cases for Some Access Traits</a></h2> <ol class="arabic">
<div class="section" id="id1"> <li><p class="first">Remove the <tt class="literal"><span class="pre">is_writable</span></tt> and <tt class="literal"><span class="pre">is_swappable</span></tt> traits, and remove the
<h3><a class="toc-backref" href="#id11" name="id1"><tt class="literal"><span class="pre">is_swappable_iterator</span></tt></a></h3> requirements in the Writable Iterator and Swappable Iterator concepts
<p><tt class="literal"><span class="pre">is_swappable_iterator&lt;I&gt;</span></tt> is supposed to yield true if that require their models to support these traits.</p>
<tt class="literal"><span class="pre">iter_swap(x,y)</span></tt> is valid for instances <tt class="literal"><span class="pre">x</span></tt> and <tt class="literal"><span class="pre">y</span></tt> of type </li>
<tt class="literal"><span class="pre">I</span></tt>. The only argument we have heard for <li><p class="first">Change the <tt class="literal"><span class="pre">is_readable</span></tt> specification to be:
<tt class="literal"><span class="pre">is_swappable_iterator</span></tt> goes something like this:</p> <tt class="literal"><span class="pre">is_readable&lt;X&gt;::type</span></tt> is <tt class="literal"><span class="pre">true_type</span></tt> if the
<blockquote> result type of <tt class="literal"><span class="pre">X::operator*</span></tt> is convertible to
<em>&quot;If</em> <tt class="literal"><span class="pre">is_swappable_iterator</span></tt> <em>yields</em> <tt class="literal"><span class="pre">false</span></tt><em>, you <tt class="literal"><span class="pre">iterator_traits&lt;X&gt;::value_type</span></tt> and is <tt class="literal"><span class="pre">false_type</span></tt>
could fall back to using copy construction and assignment on
the</em> <tt class="literal"><span class="pre">value_type</span></tt> <em>instead.&quot;</em></blockquote>
<p>This line of reasoning, however, falls down when closely examined.
To achieve the same effect using copy construction and assignment
on the iterator's <tt class="literal"><span class="pre">value_type</span></tt>, the iterator must be readable and
writable, and its <tt class="literal"><span class="pre">value_type</span></tt> must be copy-constructible. But
then, <tt class="literal"><span class="pre">iter_swap</span></tt> must work in that case, because its default
implementation just calls <tt class="literal"><span class="pre">swap</span></tt> on the dereferenced iterators.
The only purpose for the swappable iterator concept is to represent
iterators which do not fulfill the properties listed above, but
which are nonetheless swappable because the user has provided an
overload or specialization of <tt class="literal"><span class="pre">iter_swap</span></tt>. In other words,
generic code which wants to swap the referents of two iterators
should <em>always</em> call <tt class="literal"><span class="pre">iter_swap</span></tt> instead of doing the
assignments.</p>
</div>
<div class="section" id="id2">
<h3><a class="toc-backref" href="#id12" name="id2"><tt class="literal"><span class="pre">is_writable_iterator</span></tt></a></h3>
<p>Try to imagine a case where <tt class="literal"><span class="pre">is_writable_iterator</span></tt> can be used to
choose behavior. Since the only requirement on a writable iterator
is that we can assign into its referent, the only use for
<tt class="literal"><span class="pre">is_writable_iterator</span></tt> in selecting behavior is to modify a
sequence when the sequence is mutable, and to not modify it
otherwise.</p> otherwise.</p>
<p>There is no precedent for generic functions which modify their <p>Remove the requirement for support of the <tt class="literal"><span class="pre">is_readable</span></tt> trait from
arguments only if the arguments are non-const reference, and with the Readable Iterator concept.</p>
good reason: the simple fact that data is mutable does not mean </li>
that a user <em>intends</em> it to be mutated. We provide <tt class="literal"><span class="pre">const</span></tt> and </ol>
non-<tt class="literal"><span class="pre">const</span></tt> overloads for functions like <tt class="literal"><span class="pre">operator[]</span></tt>, but <!-- We should give some attention to the UnaryTypeTrait concept,
these do not modify data; they merely return a reference to data which requires the trait to be derived from either true_type or
which preserves the object's mutability properties. We can do the false_type (as of the last LWG meeting). -->
same with iterators using their <tt class="literal"><span class="pre">reference</span></tt> types; the <ol class="arabic" start="3">
accessibility of an assignment operator on the <tt class="literal"><span class="pre">value_type</span></tt>, <li><p class="first">Change <tt class="literal"><span class="pre">iterator_tag</span></tt> to:</p>
which determines writability, does not change that.</p>
<p>The one plausible argument we can imagine for
<tt class="literal"><span class="pre">is_writable_iterator</span></tt> and <tt class="literal"><span class="pre">is_swappable_iterator</span></tt> is that they
can be used to remove algorithms from an overload set using a
SFINAE technique like <a class="reference" href="http://tinyurl.com/tsr7">enable_if</a>, thus minimizing unintentional
matches due to Koenig Lookup. If it means requiring explicit
indications of writability and swappability from new-style iterator
implementors, however, it seems to be too small a gain to be worth
the cost. That's especially true since we can't get many existing
old-style iterators to meet the same requirements.</p>
</div>
</div>
<div class="section" id="naming-issues">
<h2><a class="toc-backref" href="#id13" name="naming-issues">Naming Issues</a></h2>
<div class="section" id="traversal-concepts-and-tags">
<h3><a class="toc-backref" href="#id14" name="traversal-concepts-and-tags">Traversal Concepts and Tags</a></h3>
<p>Howard Hinnant pointed out some inconsistencies with the naming of
these tag types:</p>
<pre class="literal-block"> <pre class="literal-block">
incrementable_iterator_tag // ++r, r++ template &lt;class Value, class Reference, class Traversal&gt;
single_pass_iterator_tag // adds a == b, a != b struct iterator_tag;
forward_traversal_iterator_tag // adds multi-pass capability
bidirectional_traversal_iterator_tag // adds --r, r--
random_access_traversal_iterator_tag // adds r+n,n+r,r-n,r[n],etc.
</pre> </pre>
<p>Howard thought that it might be better if all tag names contained <p>The argument for <tt class="literal"><span class="pre">Value</span></tt> must be the <tt class="literal"><span class="pre">value_type</span></tt> of the
the word &quot;traversal&quot;.</p> iterator, possibly const-qualified, <tt class="literal"><span class="pre">Reference</span></tt> must be the
<p>It's not clear that would result in the best possible names, return type of <tt class="literal"><span class="pre">operator*</span></tt> <a class="footnote-reference" href="#id2" id="id1" name="id1"><sup>*</sup></a>, and <tt class="literal"><span class="pre">Traversal</span></tt> the
though. For example, incrementable iterators can only make a traversal tag for the iterator.</p>
single pass over their input. What really distinguishes single </li>
pass iterators from incrementable iterators is not that they can </ol>
make a single pass, but that they are equality comparable. Forward <!-- I think the language above is still too informal. There is no
traversal iterators really distinguish themselves by introducing "the iterator", when considering iterator_tag in isolation.
multi-pass capability. Without entering a &quot;Parkinson's Bicycle Perhaps that language belongs in a non-normative note
Shed&quot; type of discussion, it might be worth giving the names of
these tags (and the associated concepts) some extra attention.</p> ``iterator_tag<Value,Reference,Traversal>`` is required to be
</div> convertible to both ``Traversal`` tag and also to the
<div class="section" id="access-traits"> ``iterator_category`` type specified by the following
<h3><a class="toc-backref" href="#id15" name="access-traits">Access Traits</a></h3> pseudo-code::
<p>The names <tt class="literal"><span class="pre">is_readable</span></tt>, <tt class="literal"><span class="pre">is_writable</span></tt>, and <tt class="literal"><span class="pre">is_swappable</span></tt>
are probably too general for their semantics. In particular, a old-category(Value, Reference, Traversal) =
swappable iterator is only swappable in the same sense that a if (Reference is a reference
mutable iterator is mutable: the trait refers to the iterator's and Traversal is convertible to forward_traversal_tag)
referent. It would probably be better to add the <tt class="literal"><span class="pre">_iterator</span></tt> {
suffix to each of these names.</p> if (Traversal is convertible to random_access_traversal_tag)
</div> return random_access_iterator_tag;
</div> else if (Traversal is convertible to bidirectional_traversal_tag)
</div> return bidirectional_iterator_tag;
<div class="section" id="proposed-solution-in-progress"> else
<h1><a class="toc-backref" href="#id16" name="proposed-solution-in-progress">Proposed Solution (in progress)</a></h1> return forward_iterator_tag;
<p>We believe that <tt class="literal"><span class="pre">is_readable_iterator</span></tt> is a fine name for the }
proposed <tt class="literal"><span class="pre">is_readable</span></tt> trait and will use that from here on. In else if (Traversal is convertible to single_pass_traversal_tag
order to avoid confusion, however, and because we aren't terribly and Reference is convertible to Value)
convinced of any answer yet, we are going to phrase this solution {
in terms of the existing traversal concept and tag names. We'll if (Value is const)
propose a few possible traversal naming schemes at the end of this return input_iterator_tag;
section.</p> else
<div class="section" id="overview"> return input_output_iterator_tag;
<h2><a class="toc-backref" href="#id17" name="overview">Overview</a></h2> } else
<p>Following the dictum that what we can't do well probably shouldn't return output_iterator_tag; -->
be done at all, we'd like to solve many of the problems above by <!-- I reformatted the code for legibility; sorry. -->
eliminating details and simplifying the library as proposed. In <table class="footnote" frame="void" id="id2" rules="none">
particular, we'd eliminate <tt class="literal"><span class="pre">is_writable</span></tt> and <tt class="literal"><span class="pre">is_swappable</span></tt>, <colgroup><col class="label" /><col /></colgroup>
and remove the requirements which say that writable, and swappable <tbody valign="top">
iterators must support these traits. <tt class="literal"><span class="pre">is_readable_iterator</span></tt> has <tr><td class="label"><a class="fn-backref" href="#id1" name="id2">[*]</a></td><td>Instead of saying &quot;return type of operator*&quot;, we could have
proven to be useful and will be retained, but since it can be said <tt class="literal"><span class="pre">iterator_traits&lt;X&gt;::reference</span></tt>. However, the standard
implemented with no special hints from the iterator, it will not be specifies nothing about <tt class="literal"><span class="pre">iterator_traits&lt;X&gt;::reference</span></tt> in
mentioned in the readable iterator requirements. Since we don't many cases, which we believe is a defect. Furthermore, in some
want to require the user to explicitly specify access category cases it explicitly differs from the return type of
information, we'll change <tt class="literal"><span class="pre">iterator_tag</span></tt> so that it computes the <tt class="literal"><span class="pre">operator*</span></tt>, for example see <tt class="literal"><span class="pre">istreambuf_iterator</span></tt>.</td></tr>
old-style category in terms of the iterator's traversal category, </tbody>
<tt class="literal"><span class="pre">reference</span></tt>, and <tt class="literal"><span class="pre">value_type</span></tt>.</p> </table>
</div> <ol class="arabic" start="4">
<div class="section" id="future-enhancements"> <li><p class="first">Change the specification of <tt class="literal"><span class="pre">traversal_category</span></tt> to:</p>
<h2><a class="toc-backref" href="#id18" name="future-enhancements">Future Enhancements</a></h2>
<p>For C++0x, we could consider a change to <tt class="literal"><span class="pre">iterator_traits</span></tt> which
allows the user to avoid the use of iterator_tag (or similar
devices) altogether and write a new-style iterator by specifying
only a traversal tag. This change is not being proposed as it does
not constitute a &quot;pure bolt-on&quot;:</p>
<pre class="literal-block"> <pre class="literal-block">
iterator_traits&lt;I&gt;::iterator_category traversal-category(Iterator) =
= if (I::iterator_category is a type) // use mpl::has_xxx (SFINAE) let cat = iterator_traits&lt;Iterator&gt;::iterator_category
return I::iterator_category if (cat is convertible to incrementable_iterator_tag)
return cat; // Iterator is a new iterator
// Only old-style output iterators may have a void value_type else if (cat is convertible to random_access_iterator_tag)
// or difference_type return random_access_traversal_tag;
if (iterator_value_type&lt;I&gt;::type is void else if (cat is convertible to bidirectional_iterator_tag)
|| iterator_difference_type&lt;I&gt;::type is void return bidirectional_traversal_tag;
) else if (cat is convertible to forward_iterator_tag)
return std::output_iterator_tag return forward_traversal_tag;
else if (cat is convertible to input_iterator_tag)
t = iterator_traversal&lt;I&gt;::type return single_pass_iterator_tag;
else if (cat is convertible to output_iterator_tag)
if (I is an lvalue iterator) return incrementable_iterator_tag;
{
if (t is convertible to random_access_traversal_tag)
return std::random_access_iterator_tag
if (t is convertible to bidirectional_traversal_tag)
return std::bidirectional_iterator_tag
else if (t is convertible to forward_traversal_tag)
return std::forward_iterator_tag
}
if (t is convertible to single_pass_traversal_tag
&amp;&amp; I is a readable iterator
)
return input_output_iterator_tag // (**)
else else
return std::output_iterator_tag return null_category_tag;
</pre> </pre>
</li>
</ol>
</div> </div>
<div class="section" id="impact-on-n1530-iterator-facade-and-adaptor"> <div class="section" id="rationale">
<h2><a class="toc-backref" href="#id19" name="impact-on-n1530-iterator-facade-and-adaptor">Impact on <a class="reference" href="http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1530.html">N1530</a> (Iterator Facade and Adaptor)</a></h2> <h1><a class="toc-backref" href="#id5" name="rationale">Rationale</a></h1>
<p>XXX</p> <ol class="arabic simple">
</div> <li>There are two reasons for removing <tt class="literal"><span class="pre">is_writable</span></tt>
and <tt class="literal"><span class="pre">is_swappable</span></tt>. 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 <tt class="literal"><span class="pre">is_writable</span></tt> and <tt class="literal"><span class="pre">is_swappable</span></tt>
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.</li>
<li>We discovered that the <tt class="literal"><span class="pre">is_readable</span></tt> trait can be implemented
using only the iterator type itself and its <tt class="literal"><span class="pre">value_type</span></tt>.
Therefore we remove the requirement for <tt class="literal"><span class="pre">is_readable</span></tt> from the
Readable Iterator concept, and change the definition of
<tt class="literal"><span class="pre">is_readable</span></tt> so that it works for any iterator type.</li>
<li>With <tt class="literal"><span class="pre">is_writable</span></tt> and <tt class="literal"><span class="pre">is_swappable</span></tt> gone, and
<tt class="literal"><span class="pre">is_readable</span></tt> no longer in need of special hints,
there is no reason for the <tt class="literal"><span class="pre">iterator_tag</span></tt> class to provide
information about the access capabilities of an iterator.
This new version provides only information about the traversal
capabilities and the old iterator category tag. Instead of accessing
the traversal category as a nested typedef <tt class="literal"><span class="pre">::traversal</span></tt>,
the <tt class="literal"><span class="pre">iterator_tag</span></tt> itself will be convertible to the traversal
tag. The <tt class="literal"><span class="pre">access_bits</span></tt> parameter is no longer needed for
specifying the access member (which is now gone). However,
some access information is still needed so that we can
deduce the appropriate old iterator category. The
<tt class="literal"><span class="pre">Value</span></tt> and <tt class="literal"><span class="pre">Reference</span></tt> parameters fill this need.
Note that this solution cleans up the issue that John
Maddock raised on the reflector (<tt class="literal"><span class="pre">c++std-lib-12187</span></tt>) about the non-uniformity
of the lvalue bit.</li>
<li>The changes to the specification of <tt class="literal"><span class="pre">traversal_category</span></tt> are a
direct result of the changes to <tt class="literal"><span class="pre">iterator_tag</span></tt>.</li>
</ol>
</div> </div>
</div> </div>
<hr class="footer" /> <hr class="footer" />
<div class="footer"> <div class="footer">
<a class="reference" href="issues.rst">View document source</a>. <a class="reference" href="issues.rst">View document source</a>.
Generated on: 2003-11-07 19:02 UTC. Generated on: 2003-11-17 17:15 UTC.
Generated by <a class="reference" href="http://docutils.sourceforge.net/">Docutils</a> from <a class="reference" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> source. Generated by <a class="reference" href="http://docutils.sourceforge.net/">Docutils</a> from <a class="reference" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> source.
</div> </div>
</body> </body>

View File

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