<!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">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <meta http-equiv="Content-Style-Type" content="text/css" />
  <meta name="generator" content="pandoc" />
  <title>I Stream, You Stream, We All Stream for istream_iterator</title>
  <style type="text/css">code{white-space: pre;}</style>
  <style type="text/css">
a.sourceLine { display: inline-block; line-height: 1.25; }
a.sourceLine { pointer-events: none; color: inherit; text-decoration: inherit; }
a.sourceLine:empty { height: 1.2em; position: absolute; }
.sourceCode { overflow: visible; }
code.sourceCode { white-space: pre; position: relative; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
code.sourceCode { white-space: pre-wrap; }
a.sourceLine { text-indent: -1em; padding-left: 1em; }
}
pre.numberSource a.sourceLine
  { position: relative; }
pre.numberSource a.sourceLine:empty
  { position: absolute; }
pre.numberSource a.sourceLine::before
  { content: attr(data-line-number);
    position: absolute; left: -5em; text-align: right; vertical-align: baseline;
    border: none; pointer-events: all;
    -webkit-touch-callout: none; -webkit-user-select: none;
    -khtml-user-select: none; -moz-user-select: none;
    -ms-user-select: none; user-select: none;
    padding: 0 4px; width: 4em;
    color: #aaaaaa;
  }
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
div.sourceCode
  {  }
@media screen {
a.sourceLine::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
  </style>
  <style type="text/css">
  ins {
    color:#009a9a; text-decoration:underline;
  }
  
  del {
    color:red; text-decoration:line-through;
  }
  
  ednote {
    color:blue;
  }
  
  table {
    border-collapse: collapse;
  }
  
  table, th, td {
    border: 1px solid black;
  }
  
  code.diff > span.st {
    color: darkred;
  }
  </style>
</head>
<body>
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="607">
  <tr>
    <td width="172" align="left" valign="top">Document number:</td>
    <td width="435">P0738R2</td>
  </tr>
  <tr>
    <td width="172" align="left" valign="top">Date:</td>
    <td width="435">2019-02-21</td>
  </tr>
  <tr>
    <td width="172" align="left" valign="top">Project:</td>
    <td width="435">C++ Programming Language, Library Working Group</td>
  </tr>
  <tr>
    <td width="172" align="left" valign="top">Reply-to:</td>
    <td width="435">Casey Carter &lt;<a href="mailto:Casey@Carter.net">Casey@Carter.net</a>&gt;<br></td>
  </tr>
</table>
<div id="header">
<h1 class="title">I Stream, You Stream, We All Stream for <code>istream_iterator</code></h1>
</div>
<h2>Abstract</h2>
<p>The specification and design of <code>istream_iterator</code> have some problems. First, the specification in the Standard begins with two paragraphs ([istream.iterator]/1 and /2) that intermix semi-normative description with actual normative requirements. This results in requirements that are either redundant, or are far from the entity whose behavior they are intended to describe. These normative requirements should be in the specification of the individual member functions. The current situation is both confusing and inconsistent with the specification of other library components.</p>
<p>Second, the semantics of exactly when an <code>istream_iterator</code> performs a read from its underlying input stream are unclear. The specification purports to allow an implementation to delay reading the initial value from the stream, which has been a source of confusion in the past (<a href="http://cplusplus.github.io/LWG/lwg-closed.html#245">LWG 245 “Which operations on <code>istream_iterator</code> trigger input operations?”</a>). This program, for example:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb1-1" data-line-number="1">istream_iterator&lt;<span class="dt">int</span>&gt;{cin};</a>
<a class="sourceLine" id="cb1-2" data-line-number="2">istream_iterator&lt;<span class="dt">int</span>&gt;{cin};</a>
<a class="sourceLine" id="cb1-3" data-line-number="3">istream_iterator&lt;<span class="dt">int</span>&gt;{cin};</a>
<a class="sourceLine" id="cb1-4" data-line-number="4">istream_iterator&lt;<span class="dt">int</span>&gt;{cin};</a>
<a class="sourceLine" id="cb1-5" data-line-number="5">istream_iterator&lt;<span class="dt">int</span>&gt;{cin};</a></code></pre></div>
<p>is specified to read between zero and five integers from the standard input. We argue that an implementation that delays reading the initial value from the stream cannot, in fact, conform to the input iterator requirements.</p>
<p>While correcting these two specification problems we also propose some cleanup and modernization of the specification of <code>istream_iterator</code> in passing.</p>
<h2>Revision History</h2>
<h4>Revision 2</h4>
<ul>
<li>LWG feedback:
<ul>
<li>Throughout: Add “is <code>true</code>” to raw predicates in elements.</li>
<li>[istream.iterator.ops]/4: Add “Equivalent to:” and wrap codeblock.</li>
</ul></li>
</ul>
<h4>Revision 1</h4>
<ul>
<li>Struck proposed modifications to the Ranges TS, which is effectively dead after merging <a href="https://wg21.link/p0896r4">P0896R4 “The One Ranges Proposal”</a> to the working draft.</li>
<li>Rebase proposed changes onto the post-San Diego working draft.</li>
<li>Updated the style of specification to use the specification elements introduced by <a href="https://wg21.link/p0788r3">P0788R3 “Standard Library Specification in a Concepts and Contracts World”</a>.</li>
<li>Split “this thingy is a <code>constexpr</code> thingy” wording out of “Effects” and into “Remarks”.</li>
</ul>
<h2>Discussion</h2>
<h3><code>istream_iterator</code>’s jumbled introduction</h3>
<p>The presentation of many Standard Library classes follows a common structure:</p>
<ul>
<li>a paragraph with a brief general introduction</li>
<li>a class synopsis</li>
<li>a few paragraphs of class-specifiec normative requirements (“template parameter <code>T</code> must be an object type that meets the <code>Destructible</code> requirements” … “template parameter <code>T</code> may be an incomplete type”)</li>
<li>a detailed specification of the class’s member functions and their individual behaviors</li>
</ul>
<p><code>istream_iterator</code> does not follow that structure, despite appearing to do so. Its introductory paragraphs are <em>not</em> brief, and verge on tutorial: “It is impossible to store things into istream iterators.” It contains normative requirements that in some cases duplicate requirements in the specification of the individual member functions (“Two end-of-stream iterators are always equal”), and in other cases are the only occurrence of a requirement that <em>should</em> appear in the specification of a member function (“If the iterator fails to read and store a value of <code>T</code> (<code>fail()</code> on the stream returns <code>true</code>), the iterator becomes equal to the end-of-stream iterator value”). Removing duplicate requirements and relocating non-duplicate requirements to the specification of the entity to which they apply would improve the quality and consistency of the specification.</p>
<h3>Confused postcondition</h3>
<p>The specification of <code>istream_iterator</code>’s constructor from <code>istream_type&amp;</code> ([istream.iterator.cons] para 3 and 4):</p>
<blockquote>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb2-1" data-line-number="1">  istream_iterator(<span class="dt">istream_type</span>&amp; s);</a></code></pre></div>
<p>3 <em>Effects:</em> Initializes <code>in_stream</code> with <code>std::addressof(s)</code>. <code>value</code> may be initialized during construction or the first time it is referenced.</p>
<p>4 <em>Postcondition:</em> <code>in_stream == &amp;s</code>.</p>
</blockquote>
<p>The postcondition in para 4 is (a) redundant with the effect “initializes <code>in_stream</code> with …”, and (b) flat out wrong if the implementation tries to read the first <code>value</code> from the stream and immediately hits end-of-stream. We propose simply removing this postcondition paragraph.</p>
<h3>Delayed-initialization semantics</h3>
<p><code>istream_iterator</code> purports to allow implementations that delay reading the first value from the stream until it is needed ([istream.iterator.cons]/3 “<code>value</code> may be initialized during construction or the first time it is referenced”). Consider this program fragment:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb3-1" data-line-number="1">istream_iterator&lt;<span class="dt">int</span>&gt; i1(cin);</a>
<a class="sourceLine" id="cb3-2" data-line-number="2"><span class="kw">auto</span> i2 = i1;</a>
<a class="sourceLine" id="cb3-3" data-line-number="3">assert(*i1 == *i2);</a></code></pre></div>
<p>We claim that this program does not <code>assert</code>. In the Ranges TS, iterator copies must be <em>equal</em> - meaning they can be substituted into expressions designated as equality-preserving - and <code>*i</code> is exactly such an expression. Since there are no intervening modifications between the copy construction of <code>i2</code> and the assertion, it must be the case that <code>*i1 == *i2</code>. For Standard C++, the semantics are less clear: copies are required to be equivalent (Table 24 <code>CopyConstructible</code> requirements), although the the meaning of the term “equivalent” in this context is not clearly defined. It’s not unreasonable to interpret “equivalent” in this context to mean something similar to the more concrete semantics given in the Ranges TS. One of the primary goals of the Ranges TS is to more clearly specify the semantics of the standard library for cases such as this, and presumably the TS WP reflects WG21’s intent for iterators and algorithms fairly well.</p>
<p>An implementation of <code>istream_iterator</code> that reads the initial value on construction and never delays initialization obviously satisfies the preceding requirements: the value stored in <code>i1</code> is copied into <code>i2</code>, those copies are obviously equal in the assertion. Can an implementation that delays initialization meet that bar?</p>
<p>For an implementation that delays initialization to work it must read the initial value from the stream sometime between the construction of <code>i1</code> and the dereference of <code>i1</code> in the assertion. That leaves two possible points for the delayed init to occur:</p>
<ul>
<li><p>in the copy constructor that initializes <code>i2</code> from <code>i1</code>. This is not possible, since [istream.iterator.cons]/5 requires the copy constructor to be trivial when <code>T</code> is a trivially copyable (Standard) / literal (Ranges TS) type.</p></li>
<li><p>in the first evaluated dereference operator that reads the value of <code>i1</code> or <code>i2</code>. For this to work the <em>second</em> dereference operator evaluation must see the same value, so there must be some connection between the two iterator objects that is set up in the trivial copy constructor and torn down again in the trivial destructor. We do not believe that forming such an association between two objects is possible given the constraints that the copy constructor and destructor must be trivial: any external memory/resource used to coordinate communication between the objects must necessarily leak.</p></li>
</ul>
<p>On the basis of this argument that a conforming implementation <em>cannot</em> delay initialization, we propose to remove the allowance to do so thereby simplifying the specification and clarifying the semantics of <code>istream_iterator</code>.</p>
<h2>Technical Specifications</h2>
<p>All wording relative to the post-San Diego C++ working draft.</p>
<p>Strike all but the first sentence of <a href="https://wg21.link/istream.iterator#1">[istream.iterator]/1</a>, and the text of <a href="https://wg21.link/istream.iterator#2">paragraph 2</a>:</p>
<blockquote>
<p>1 The class template <code>istream_iterator</code> is an input iterator (<a href="https://wg21.link/input.iterators">[input.iterators]</a>) that reads <del>(using <code>operator&gt;&gt;</code>)</del> successive elements from the input stream for which it was constructed. <del>After it is constructed, and every time <code>++</code> is used, the iterator reads and stores a value of <code>T</code>. If the iterator fails to read and store a value of <code>T</code> (<code>fail()</code> on the stream returns <code>true</code>), the iterator becomes equal to the <em>end-of-stream</em> iterator value. The constructor with no arguments <code>istream_iterator()</code> always constructs an end-of-stream input iterator object, which is the only legitimate iterator to be used for the end condition. The result of <code>operator*</code> on an end-of-stream iterator is not defined. For any other iterator value a <code>const T&amp;</code> is returned. The result of <code>operator-&gt;</code> on an end-of-stream iterator is not defined. For any other iterator value a <code>const T*</code> is returned. The behavior of a program that applies <code>operator++()</code> to an end-of-stream iterator is undefined. It is impossible to store things into istream iterators. The type <code>T</code> shall satisfy the <em><code>Cpp17DefaultConstructible</code></em>, <em><code>Cpp17CopyConstructible</code></em>, and <em><code>Cpp17CopyAssignable</code></em> requirements.</del></p>
<p>2 <del>Two end-of-stream iterators are always equal. An end-of-stream iterator is not equal to a non-end-of-stream iterator. Two non-end-of-stream iterators are equal when they are constructed from the same stream.</del></p>
</blockquote>
<p>Add a new paragraph to the end of <a href="https://wg21.link/istream.iterator">[istream.iterator]</a>, after the class synopsis:</p>
<blockquote>
<p>-?- <ins>The type <code>T</code> shall meet the <em><code>Cpp17DefaultConstructible</code></em>, <em><code>Cpp17CopyConstructible</code></em>, and <em><code>Cpp17CopyAssignable</code></em> requirements.</ins></p>
</blockquote>
<p>Modify <a href="https://wg21.link/istream.iterator.cons">[istream.iterator.cons]</a> as follows:</p>
<blockquote>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb4-1" data-line-number="1">  <span class="kw">constexpr</span> istream_iterator();</a>
<a class="sourceLine" id="cb4-2" data-line-number="2">  <span class="kw">constexpr</span> istream_iterator(<span class="dt">default_sentinel_t</span>);</a></code></pre></div>
<p>1 <em>Effects:</em> Constructs the end-of-stream iterator<ins>, value-initializing <code>value</code></ins>. <del>If <code>is_trivially_default_constructible_v&lt;T&gt;</code> is <code>true</code>, then these constructors are constexpr constructors.</del></p>
<p>2 <em>Ensures:</em> <code>in_stream == <del>0</del><ins>nullptr</ins></code> <ins>is <code>true</code></ins>.</p>
<p>-?- <ins><em>Remarks:</em> If the initializer <code>T()</code> in the declaration <code>auto x = T();</code> is a constant initializer (<a href="https://wg21.link/expr.const#2">[expr.const]</a>), then these constructors are <code>constexpr</code> constructors.</ins></p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb5-1" data-line-number="1">  istream_iterator(<span class="dt">istream_type</span>&amp; s);</a></code></pre></div>
<p>3 <em>Effects:</em> Initializes <code>in_stream</code> with <code>addressof(s)</code><ins>, value-initializes <code>value</code>, and then calls <code>operator++()</code></ins>. <del><code>value</code> may be initialized during construction or the first time it is referenced.</del></p>
<p>4 <del><em>Ensures:</em> <code>in_stream == addressof(s)</code>.</del></p>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb6-1" data-line-number="1">  istream_iterator(<span class="at">const</span> istream_iterator&amp; x) = <span class="cf">default</span>;</a></code></pre></div>
<p>5 <em>Effects:</em> Constructs a copy of <code>x</code>. <del>If <code>is_trivially_copy_constructible_v&lt;T&gt;</code> is <code>true</code>, then this constructor is a trivial copy constructor.</del></p>
<p>6 <em>Ensures:</em> <code>in_stream == x.in_stream</code> <ins>is <code>true</code></ins>.</p>
<p>-?- <ins><em>Remarks:</em> If <code>is_trivially_copy_constructible_v&lt;T&gt;</code> is <code>true</code>, then this constructor is trivial.</ins></p>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb7-1" data-line-number="1">  ~istream_iterator() = <span class="cf">default</span>;</a></code></pre></div>
<p>7 <del><em>Effects:</em> The iterator is destroyed.</del> <ins><em>Remarks:</em></ins> If <code>is_trivially_destructible_v&lt;T&gt;</code> is <code>true</code>, then this destructor is trivial.</p>
</blockquote>
<p>Modify <a href="https://wg21.link/istream.iterator.ops">[istream.iterator.ops]</a> as follows:</p>
<blockquote>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb8-1" data-line-number="1">  <span class="at">const</span> T&amp; <span class="kw">operator</span>*() <span class="at">const</span>;</a></code></pre></div>
<p>-?- <ins><em>Expects:</em> <code>in_stream != nullptr</code> is <code>true</code>.</ins></p>
<p>1 <em>Returns:</em> <code>value</code>.</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb9-1" data-line-number="1">  <span class="at">const</span> T* <span class="kw">operator</span>-&gt;() <span class="at">const</span>;</a></code></pre></div>
<p>-?- <ins><em>Expects:</em> <code>in_stream != nullptr</code> is <code>true</code>.</ins></p>
<p>2 <em>Returns:</em> <code>addressof(</code><del><code>operator*()</code></del><ins><code>value</code></ins><code>)</code>.</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb10-1" data-line-number="1">  istream_iterator&amp; <span class="kw">operator</span>++();</a></code></pre></div>
<p>3 <em><del>Requires</del><ins>Expects</ins>:</em> <code>in_stream != <del>0</del><ins>nullptr</ins></code> <ins>is <code>true</code></ins>.</p>
<p>4 <em>Effects:</em> <del>As if by: <code>*in_stream &gt;&gt; value;</code></del><ins>Equivalent to:</ins></p>
<p>    <ins><code>if (!(*in_stream &gt;&gt; value))</code><br/></ins>       <ins><code>in_stream = nullptr;</code><br/></ins></p>
<p>5 <em>Returns:</em> <code>*this</code>.</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb11-1" data-line-number="1">  istream_iterator <span class="kw">operator</span>++(<span class="dt">int</span>);</a></code></pre></div>
<p>6 <del><em>Requires:</em> <code>in_stream != 0</code>.</del></p>
<p>7 <em>Effects:</em> <del>As if by:</del><ins>Equivalent to:</ins></p>
<p>    <code>istream_iterator tmp = *this;</code><br/>     <del><code>*in_stream &gt;&gt; value;</code></del><br/>     <ins><code>++*this;</code></ins><br/>     <code>return <del>(</del>tmp<del>)</del>;</code><br/></p>
<p>[…]</p>
</blockquote>
<h3>Acknowledgements</h3>
<p>I would like to thank Tim Song for pointing out to me that <code>istream_iterator::operator*</code> requires the iterator to not be an end-of-stream iterator, and that this requirement is squirreled away in <a href="https://wg21.link/istream.iterator#1">[istream.iterator]/1</a> and NOT in <a href="https://wg21.link/istream.iterator.ops">[istream.iterator.ops]</a> with the specification of <code>operator*</code> where a sane person would expect it to be.</p>
</body>
</html>
