mirror of
https://github.com/boostorg/iterator.git
synced 2025-07-19 07:32:08 +02:00
Added is_readable_iterator, is_writable_iterator tests and preliminary issues document
[SVN r20686]
This commit is contained in:
442
doc/issues.html
Executable file
442
doc/issues.html
Executable file
@ -0,0 +1,442 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="generator" content="Docutils 0.3.1: http://docutils.sourceforge.net/" />
|
||||
<title>Issues With N1550 and N1530</title>
|
||||
<style type="text/css"><!--
|
||||
|
||||
/*
|
||||
:Author: David Goodger
|
||||
:Contact: goodger@users.sourceforge.net
|
||||
:date: $Date$
|
||||
:version: $Revision$
|
||||
:copyright: This stylesheet has been placed in the public domain.
|
||||
|
||||
Default cascading style sheet for the HTML output of Docutils.
|
||||
*/
|
||||
|
||||
.first {
|
||||
margin-top: 0 }
|
||||
|
||||
.last {
|
||||
margin-bottom: 0 }
|
||||
|
||||
a.toc-backref {
|
||||
text-decoration: none ;
|
||||
color: black }
|
||||
|
||||
dd {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
div.abstract {
|
||||
margin: 2em 5em }
|
||||
|
||||
div.abstract p.topic-title {
|
||||
font-weight: bold ;
|
||||
text-align: center }
|
||||
|
||||
div.attention, div.caution, div.danger, div.error, div.hint,
|
||||
div.important, div.note, div.tip, div.warning {
|
||||
margin: 2em ;
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.attention p.admonition-title, div.caution p.admonition-title,
|
||||
div.danger p.admonition-title, div.error p.admonition-title,
|
||||
div.warning p.admonition-title {
|
||||
color: red ;
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
div.hint p.admonition-title, div.important p.admonition-title,
|
||||
div.note p.admonition-title, div.tip p.admonition-title {
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
div.dedication {
|
||||
margin: 2em 5em ;
|
||||
text-align: center ;
|
||||
font-style: italic }
|
||||
|
||||
div.dedication p.topic-title {
|
||||
font-weight: bold ;
|
||||
font-style: normal }
|
||||
|
||||
div.figure {
|
||||
margin-left: 2em }
|
||||
|
||||
div.footer, div.header {
|
||||
font-size: smaller }
|
||||
|
||||
div.system-messages {
|
||||
margin: 5em }
|
||||
|
||||
div.system-messages h1 {
|
||||
color: red }
|
||||
|
||||
div.system-message {
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.system-message p.system-message-title {
|
||||
color: red ;
|
||||
font-weight: bold }
|
||||
|
||||
div.topic {
|
||||
margin: 2em }
|
||||
|
||||
h1.title {
|
||||
text-align: center }
|
||||
|
||||
h2.subtitle {
|
||||
text-align: center }
|
||||
|
||||
hr {
|
||||
width: 75% }
|
||||
|
||||
ol.simple, ul.simple {
|
||||
margin-bottom: 1em }
|
||||
|
||||
ol.arabic {
|
||||
list-style: decimal }
|
||||
|
||||
ol.loweralpha {
|
||||
list-style: lower-alpha }
|
||||
|
||||
ol.upperalpha {
|
||||
list-style: upper-alpha }
|
||||
|
||||
ol.lowerroman {
|
||||
list-style: lower-roman }
|
||||
|
||||
ol.upperroman {
|
||||
list-style: upper-roman }
|
||||
|
||||
p.caption {
|
||||
font-style: italic }
|
||||
|
||||
p.credits {
|
||||
font-style: italic ;
|
||||
font-size: smaller }
|
||||
|
||||
p.label {
|
||||
white-space: nowrap }
|
||||
|
||||
p.topic-title {
|
||||
font-weight: bold }
|
||||
|
||||
pre.address {
|
||||
margin-bottom: 0 ;
|
||||
margin-top: 0 ;
|
||||
font-family: serif ;
|
||||
font-size: 100% }
|
||||
|
||||
pre.line-block {
|
||||
font-family: serif ;
|
||||
font-size: 100% }
|
||||
|
||||
pre.literal-block, pre.doctest-block {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em ;
|
||||
background-color: #eeeeee }
|
||||
|
||||
span.classifier {
|
||||
font-family: sans-serif ;
|
||||
font-style: oblique }
|
||||
|
||||
span.classifier-delimiter {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
span.interpreted {
|
||||
font-family: sans-serif }
|
||||
|
||||
span.option-argument {
|
||||
font-style: italic }
|
||||
|
||||
span.pre {
|
||||
white-space: pre }
|
||||
|
||||
span.problematic {
|
||||
color: red }
|
||||
|
||||
table {
|
||||
margin-top: 0.5em ;
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
table.citation {
|
||||
border-left: solid thin gray ;
|
||||
padding-left: 0.5ex }
|
||||
|
||||
table.docinfo {
|
||||
margin: 2em 4em }
|
||||
|
||||
table.footnote {
|
||||
border-left: solid thin black ;
|
||||
padding-left: 0.5ex }
|
||||
|
||||
td, th {
|
||||
padding-left: 0.5em ;
|
||||
padding-right: 0.5em ;
|
||||
vertical-align: top }
|
||||
|
||||
th.docinfo-name, th.field-name {
|
||||
font-weight: bold ;
|
||||
text-align: left ;
|
||||
white-space: nowrap }
|
||||
|
||||
h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
|
||||
font-size: 100% }
|
||||
|
||||
tt {
|
||||
background-color: #eeeeee }
|
||||
|
||||
ul.auto-toc {
|
||||
list-style-type: none }
|
||||
|
||||
--></style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="document" id="issues-with-n1550-and-n1530">
|
||||
<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>
|
||||
<table class="field-list" frame="void" rules="none">
|
||||
<col class="field-name" />
|
||||
<col class="field-body" />
|
||||
<tbody valign="top">
|
||||
<tr class="field"><th class="field-name">Author:</th><td class="field-body">David Abrahams</td>
|
||||
</tr>
|
||||
<tr class="field"><th class="field-name">Contact:</th><td class="field-body"><a class="reference" href="mailto:dave@boost-consulting.com">dave@boost-consulting.com</a></td>
|
||||
</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>
|
||||
<tr class="field"><th class="field-name">date:</th><td class="field-body">$Date$</td>
|
||||
</tr>
|
||||
<tr class="field"><th class="field-name">Copyright:</th><td class="field-body">Copyright David Abrahams 2003. Use, modification and
|
||||
distribution is subject to the Boost Software License,
|
||||
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>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="contents topic" id="table-of-contents">
|
||||
<p class="topic-title"><a name="table-of-contents">Table of Contents</a></p>
|
||||
<ul class="simple">
|
||||
<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="#non-uniformity-of-the-lvalue-iterator-bit" id="id5" name="id5">Non-Uniformity of the "<tt class="literal"><span class="pre">lvalue_iterator</span></tt> Bit"</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>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference" href="#proposed-solution" id="id13" name="id13">Proposed Solution</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="introduction">
|
||||
<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
|
||||
the run-up before the fall 2003 C++ Committee meeting, in a thread
|
||||
beginning with John Maddock's posting <tt class="literal"><span class="pre">c++std-lib-12187</span></tt>. In
|
||||
looking at those issues, several other problems came up. This
|
||||
document addresses those issues and discusses some potential
|
||||
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>
|
||||
</div>
|
||||
<div class="section" id="the-issues">
|
||||
<h1><a class="toc-backref" href="#id4" name="the-issues">The Issues</a></h1>
|
||||
<div class="section" id="non-uniformity-of-the-lvalue-iterator-bit">
|
||||
<h2><a class="toc-backref" href="#id5" name="non-uniformity-of-the-lvalue-iterator-bit">Non-Uniformity of the "<tt class="literal"><span class="pre">lvalue_iterator</span></tt> Bit"</a></h2>
|
||||
<p>The proposed <tt class="literal"><span class="pre">iterator_tag</span></tt> class template accepts an "access
|
||||
bits" parameter which includes a bit to indicate the iterator's
|
||||
<em>lvalueness</em> (whether its dereference operator returns a reference
|
||||
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>
|
||||
<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&</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">
|
||||
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;
|
||||
</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.</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<Iterator>::reference is a const reference)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
</pre>
|
||||
<p>In this case false positives are possible for non-writable forward
|
||||
iterators whose <tt class="literal"><span class="pre">reference</span></tt> type is not a reference, or as above,
|
||||
any forward, bidirectional, or random access iterator whose
|
||||
<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>
|
||||
is not assignable (e.g., because it has a private assignment
|
||||
operator).</p>
|
||||
<p>False negatives can be "reasoned away": since it is part of a
|
||||
writable iterator's concept definition that
|
||||
<tt class="literal"><span class="pre">is_writable<I>::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
|
||||
perverse use of logic, though.</p>
|
||||
<p>It might be reasonable to conclude that it is a defect that the
|
||||
standard allows forward iterators with a <tt class="literal"><span class="pre">reference</span></tt> type other
|
||||
than <tt class="literal"><span class="pre">value_type</span></tt> <em>cv</em><tt class="literal"><span class="pre">&</span></tt>, but that still leaves the problem
|
||||
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 class="section" id="no-use-cases-for-some-access-traits">
|
||||
<h2><a class="toc-backref" href="#id10" name="no-use-cases-for-some-access-traits">No Use Cases for Some Access Traits</a></h2>
|
||||
<div class="section" id="id1">
|
||||
<h3><a class="toc-backref" href="#id11" name="id1"><tt class="literal"><span class="pre">is_swappable_iterator</span></tt></a></h3>
|
||||
<p><tt class="literal"><span class="pre">is_swappable_iterator<I></span></tt> is supposed to yield true if
|
||||
<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
|
||||
<tt class="literal"><span class="pre">I</span></tt>. The only argument we have heard for
|
||||
<tt class="literal"><span class="pre">is_swappable_iterator</span></tt> goes something like this:</p>
|
||||
<blockquote>
|
||||
<em>"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
|
||||
could fall back to using copy construction and assignment on
|
||||
the</em> <tt class="literal"><span class="pre">value_type</span></tt> <em>instead."</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 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>
|
||||
<p>There is no precedent for generic functions which modify their
|
||||
arguments only if the arguments are non-const reference, and with
|
||||
good reason: the simple fact that data is mutable does not mean
|
||||
that a user <em>intends</em> it to be mutated. We provide <tt class="literal"><span class="pre">const</span></tt> and
|
||||
non-<tt class="literal"><span class="pre">const</span></tt> overloads for functions like <tt class="literal"><span class="pre">operator[]</span></tt>, but
|
||||
these do not modify data; they merely return a reference to data
|
||||
which preserves the object's mutability properties. We can do the
|
||||
same with iterators using their <tt class="literal"><span class="pre">reference</span></tt> types; the
|
||||
accessibility of an assignment operator on the <tt class="literal"><span class="pre">value_type</span></tt>,
|
||||
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 to remove
|
||||
algorithms from an overload set using a SFINAE technique like
|
||||
<a class="reference" href="http://tinyurl.com/tsr7">enable_if</a>, but that seems to be too small a gain for the
|
||||
requirements imposed on iterator implementors by the need to report
|
||||
writability and swappability, especially since it can't be done
|
||||
correctly for all existing iterators.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="proposed-solution">
|
||||
<h1><a class="toc-backref" href="#id13" name="proposed-solution">Proposed Solution</a></h1>
|
||||
<p>(incomplete)</p>
|
||||
<p>Change <tt class="literal"><span class="pre">iterator_traits</span></tt> as follows:</p>
|
||||
<pre class="literal-block">
|
||||
iterator_traits<I>::iterator_category
|
||||
= if (I::iterator_category is a type) // use mpl::has_xxx (SFINAE)
|
||||
return I::iterator_category
|
||||
|
||||
if (iterator_value_type<I>::type is void
|
||||
|| iterator_difference_type<I>::type is void
|
||||
)
|
||||
return std::output_iterator_tag
|
||||
|
||||
t = iterator_traversal<I>::type
|
||||
|
||||
if (is_lvalue_iterator<I>::value)
|
||||
{
|
||||
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
|
||||
&& is_readable_iterator<I>::value
|
||||
)
|
||||
return input_output_iterator_tag // (**)
|
||||
else
|
||||
return std::output_iterator_tag
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="footer" />
|
||||
<div class="footer">
|
||||
<a class="reference" href="issues.rst">View document source</a>.
|
||||
Generated on: 2003-11-05 21:37 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.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
229
doc/issues.rst
Executable file
229
doc/issues.rst
Executable file
@ -0,0 +1,229 @@
|
||||
+++++++++++++++++++++++++++++++
|
||||
Issues With N1550_ and N1530_
|
||||
+++++++++++++++++++++++++++++++
|
||||
|
||||
.. _N1550: http://www.boost-consulting.com/writing/n1550.html
|
||||
.. _N1530: http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1530.html
|
||||
|
||||
:Author: David Abrahams
|
||||
:Contact: dave@boost-consulting.com
|
||||
:Organization: `Boost Consulting`_
|
||||
:date: $Date$
|
||||
:Copyright: Copyright David Abrahams 2003. Use, modification and
|
||||
distribution is subject to the Boost Software License,
|
||||
Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
|
||||
at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
.. _`Boost Consulting`: http://www.boost-consulting.com
|
||||
|
||||
.. contents:: Table of Contents
|
||||
|
||||
==============
|
||||
Introduction
|
||||
==============
|
||||
|
||||
Several issues with N1550_ (New Iterator Concepts) were raised in
|
||||
the run-up before the fall 2003 C++ Committee meeting, in a thread
|
||||
beginning with John Maddock's posting ``c++std-lib-12187``. In
|
||||
looking at those issues, several other problems came up. This
|
||||
document addresses those issues and discusses some potential
|
||||
solutions and their impact on N1530_ (Iterator Facade and Adaptor).
|
||||
|
||||
============
|
||||
The Issues
|
||||
============
|
||||
|
||||
Non-Uniformity of the "``lvalue_iterator`` Bit"
|
||||
===============================================
|
||||
|
||||
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_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 ``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.
|
||||
|
||||
Redundancy of Some Explicit Access Category Flags
|
||||
=================================================
|
||||
|
||||
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.
|
||||
|
||||
New Access Traits Templates Wrong For Some Iterators
|
||||
====================================================
|
||||
|
||||
``is_writable_iterator``
|
||||
------------------------
|
||||
|
||||
The part of the ``is_writable_iterator`` trait definition which
|
||||
applies to old-style iterators is::
|
||||
|
||||
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;
|
||||
|
||||
The current forward iterator requirements place no constraints on
|
||||
the iterator's ``reference`` type, so the logic above will give
|
||||
false negatives for some otherwise-writable forward iterators whose
|
||||
``reference`` type is not a mutable reference. Also, it will
|
||||
report false positives for any forward, bidirectional, or random
|
||||
access iterator whose ``reference`` is a mutable reference but
|
||||
whose ``value_type`` is not assignable.
|
||||
|
||||
``is_swappable_iterator``
|
||||
-------------------------
|
||||
|
||||
Similarly, the part of ``is_swappable_iterator`` which applies to
|
||||
old-style iterators is::
|
||||
|
||||
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;
|
||||
|
||||
In this case false positives are possible for non-writable forward
|
||||
iterators whose ``reference`` type is not a reference, or as above,
|
||||
any forward, bidirectional, or random access iterator whose
|
||||
``reference`` is not a constant reference but whose ``value_type``
|
||||
is not assignable (e.g., because it has a private assignment
|
||||
operator).
|
||||
|
||||
False negatives can be "reasoned away": since it is part of a
|
||||
writable iterator's concept definition that
|
||||
``is_writable<I>::value`` is ``true``, any iterator for which
|
||||
it is ``false`` is by definition not writable. This seems like a
|
||||
perverse use of logic, though.
|
||||
|
||||
It might be reasonable to conclude that it is a defect that the
|
||||
standard allows forward iterators with a ``reference`` type other
|
||||
than ``value_type`` *cv*\ ``&``, but that still leaves the problem
|
||||
of old-style iterators whose ``value_type`` is not assignable. It
|
||||
is not possible to correctly compute writability and swappability
|
||||
for those old-style iterators without intervention
|
||||
(specializations of ``is_writable_iterator`` and
|
||||
``is_swappable_iterator``) from a user.
|
||||
|
||||
No Use Cases for Some Access Traits
|
||||
===================================
|
||||
|
||||
``is_swappable_iterator``
|
||||
-------------------------
|
||||
|
||||
``is_swappable_iterator<I>`` is supposed to yield true if
|
||||
``iter_swap(x,y)`` is valid for instances ``x`` and ``y`` of type
|
||||
``I``. The only argument we have heard for
|
||||
``is_swappable_iterator`` goes something like this:
|
||||
|
||||
*"If* ``is_swappable_iterator`` *yields* ``false``\ *, you
|
||||
could fall back to using copy construction and assignment on
|
||||
the* ``value_type`` *instead."*
|
||||
|
||||
This line of reasoning, however, falls down when closely examined.
|
||||
To achieve the same effect using copy construction and assignment
|
||||
on the iterator's ``value_type``, the iterator must be readable and
|
||||
writable, and its ``value_type`` must be copy-constructible. But
|
||||
then, ``iter_swap`` must work in that case, because its default
|
||||
implementation just calls ``swap`` 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 ``iter_swap``. In other words,
|
||||
generic code which wants to swap the referents of two iterators
|
||||
should *always* call ``iter_swap`` instead of doing the
|
||||
assignments.
|
||||
|
||||
``is_writable_iterator``
|
||||
------------------------
|
||||
|
||||
Try to imagine a case where ``is_writable_iterator`` 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
|
||||
``is_writable_iterator`` in selecting behavior is to modify a
|
||||
sequence when the sequence is mutable, and to not modify it
|
||||
otherwise.
|
||||
|
||||
There is no precedent for generic functions which modify their
|
||||
arguments only if the arguments are non-const reference, and with
|
||||
good reason: the simple fact that data is mutable does not mean
|
||||
that a user *intends* it to be mutated. We provide ``const`` and
|
||||
non-\ ``const`` overloads for functions like ``operator[]``, but
|
||||
these do not modify data; they merely return a reference to data
|
||||
which preserves the object's mutability properties. We can do the
|
||||
same with iterators using their ``reference`` types; the
|
||||
accessibility of an assignment operator on the ``value_type``,
|
||||
which determines writability, does not change that.
|
||||
|
||||
The one plausible argument we can imagine for
|
||||
``is_writable_iterator`` and ``is_swappable_iterator`` is to remove
|
||||
algorithms from an overload set using a SFINAE technique like
|
||||
enable_if_, but that seems to be too small a gain for the
|
||||
requirements imposed on iterator implementors by the need to report
|
||||
writability and swappability, especially since it can't be done
|
||||
correctly for all existing iterators.
|
||||
|
||||
.. _enable_if: http://tinyurl.com/tsr7
|
||||
|
||||
===================
|
||||
Proposed Solution
|
||||
===================
|
||||
|
||||
(incomplete)
|
||||
|
||||
Change ``iterator_traits`` as follows::
|
||||
|
||||
iterator_traits<I>::iterator_category
|
||||
= if (I::iterator_category is a type) // use mpl::has_xxx (SFINAE)
|
||||
return I::iterator_category
|
||||
|
||||
if (iterator_value_type<I>::type is void
|
||||
|| iterator_difference_type<I>::type is void
|
||||
)
|
||||
return std::output_iterator_tag
|
||||
|
||||
t = iterator_traversal<I>::type
|
||||
|
||||
if (is_lvalue_iterator<I>::value)
|
||||
{
|
||||
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
|
||||
&& is_readable_iterator<I>::value
|
||||
)
|
||||
return input_output_iterator_tag // (**)
|
||||
else
|
||||
return std::output_iterator_tag
|
||||
|
||||
|
@ -20,6 +20,8 @@ test-suite iterator
|
||||
|
||||
# These tests should work for just about everything.
|
||||
[ compile is_lvalue_iterator.cpp ]
|
||||
[ compile is_readable_iterator.cpp ]
|
||||
|
||||
[ run unit_tests.cpp ]
|
||||
[ run concept_tests.cpp ]
|
||||
[ run iterator_adaptor_cc.cpp ]
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/type_traits/broken_compiler_spec.hpp>
|
||||
#include <boost/iterator/is_lvalue_iterator.hpp>
|
||||
#include <boost/iterator.hpp>
|
||||
|
||||
// Last, for BOOST_NO_LVALUE_RETURN_DETECTION
|
||||
#include <boost/iterator/detail/config_def.hpp>
|
||||
|
Reference in New Issue
Block a user