<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 1203: More useful rvalue stream insertion</title>
<meta property="og:title" content="Issue 1203: More useful rvalue stream insertion">
<meta property="og:description" content="C++ library issue. Status: C++20">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue1203.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#C++20">C++20</a> status.</em></p>
<h3 id="1203"><a href="lwg-defects.html#1203">1203</a>. More useful rvalue stream insertion</h3>
<p><b>Section:</b> 31.7.6.6 <a href="https://wg21.link/ostream.rvalue">[ostream.rvalue]</a>, 31.7.5.6 <a href="https://wg21.link/istream.rvalue">[istream.rvalue]</a> <b>Status:</b> <a href="lwg-active.html#C++20">C++20</a>
 <b>Submitter:</b> Howard Hinnant <b>Opened:</b> 2009-09-06 <b>Last modified:</b> 2021-02-25</p>
<p><b>Priority: </b>2
</p>
<p><b>View all other</b> <a href="lwg-index.html#ostream.rvalue">issues</a> in [ostream.rvalue].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#C++20">C++20</a> status.</p>
<p><b>Discussion:</b></p>
<p>
31.7.6.6 <a href="https://wg21.link/ostream.rvalue">[ostream.rvalue]</a> was created to preserve the ability to insert
into (and extract from 31.7.5.6 <a href="https://wg21.link/istream.rvalue">[istream.rvalue]</a>) rvalue streams:
</p>

<blockquote><pre>
template &lt;class charT, class traits, class T&gt;
  basic_ostream&lt;charT, traits&gt;&amp;
  operator&lt;&lt;(basic_ostream&lt;charT, traits&gt;&amp;&amp; os, const T&amp; x);
</pre>
<blockquote>
<p>
1 <i>Effects:</i> <code>os &lt;&lt; x</code>
</p>
<p>
2 <i>Returns:</i> <code>os</code>
</p>
</blockquote>
</blockquote>

<p>
This is good as it allows code that wants to (for example) open, write to, and
close an <code>ofstream</code> all in one statement:
</p>

<blockquote><pre>
std::ofstream("log file") &lt;&lt; "Some message\n";
</pre></blockquote>

<p>
However, I think we can easily make this "rvalue stream helper" even easier to
use.  Consider trying to quickly create a formatted string.  With the current
spec you have to write:
</p>

<blockquote><pre>
std::string s = static_cast&lt;std::ostringstream&amp;&gt;(std::ostringstream() &lt;&lt; "i = " &lt;&lt; i).str();
</pre></blockquote>

<p>
This will store "<code>i = 10</code>" (for example) in the string <code>s</code>.  Note
the need to cast the stream back to <code>ostringstream&amp;</code> prior to using
the member <code>.str()</code>.  This is necessary because the inserter has cast
the <code>ostringstream</code> down to a more generic <code>ostream</code> during the
insertion process.
</p>

<p>
I believe we can re-specify the rvalue-inserter so that this cast is unnecessary.
Thus our customer now has to only type:
</p>

<blockquote><pre>
std::string s = (std::ostringstream() &lt;&lt; "i = " &lt;&lt; i).str();
</pre></blockquote>

<p>
This is accomplished by having the rvalue stream inserter return an rvalue of
the same type, instead of casting it down to the base class.  This is done by
making the stream generic, and constraining it to be an rvalue of a type derived
from <code>ios_base</code>.
</p>

<p>
The same argument and solution also applies to the inserter.  This code has been
implemented and tested.
</p>

<p><i>[
2009 Santa Cruz:
]</i></p>

<blockquote><p>
NAD Future. No concensus for change.
</p></blockquote>

<p><i>[LEWG Kona 2017]</i></p>

<p>Recommend Open: Design looks right.</p>

<p><i>[
2018-05-25, Billy O'Neal requests this issue be reopened and provides P/R
rebased against N4750
]</i></p>


<p>Billy O'Neal requests this issue be reopened, as changing operator&gt;&gt;
and operator&lt;&lt; to use perfect forwarding as described here is necessary to
implement LWG <a href="lwg-defects.html#2534" title="Constrain rvalue stream operators (Status: C++17)">2534</a><sup><a href="https://cplusplus.github.io/LWG/issue2534" title="Latest snapshot">(i)</a></sup> which was accepted. Moreover, this P/R also resolves
LWG <a href="lwg-defects.html#2498" title="operator&gt;&gt;(basic_istream&amp;&amp;, T&amp;&amp;) returns basic_istream&amp;, but should probably return 
basic_istream&amp;&amp; (Status: Resolved)">2498</a><sup><a href="https://cplusplus.github.io/LWG/issue2498" title="Latest snapshot">(i)</a></sup>.</p>

<p><strong>Previous resolution [SUPERSEDED]:</strong></p>
<blockquote class="note">
<p>
Change 31.7.5.6 <a href="https://wg21.link/istream.rvalue">[istream.rvalue]</a>:
</p>

<blockquote><pre>
template &lt;class <del>charT, class traits</del> <ins>Istream</ins>, class T&gt;
  <del>basic_istream&lt;charT, traits&gt;&amp;</del> <ins>Istream&amp;&amp;</ins>
  operator&gt;&gt;(<del>basic_istream&lt;charT, traits&gt;</del> <ins>Istream</ins>&amp;&amp; is, T&amp; x);
</pre>
<blockquote>
<p>
1 <i>Effects:</i> <code>is &gt;&gt; x</code>
</p>
<p>
2 <i>Returns:</i> <code><ins>std::move(</ins>is<ins>)</ins></code>
</p>
<p><ins>
3 <i>Remarks:</i> This signature shall participate in overload resolution if
and only if <code>Istream</code> is not an lvalue reference type and is derived from
<code>ios_base</code>.
</ins></p>
</blockquote>
</blockquote>

<p>
Change 31.7.6.6 <a href="https://wg21.link/ostream.rvalue">[ostream.rvalue]</a>:
</p>

<blockquote><pre>
template &lt;class <del>charT, class traits</del> <ins>Ostream</ins>, class T&gt;
  <del>basic_ostream&lt;charT, traits&gt;&amp;</del> <ins>Ostream&amp;&amp;</ins>
  operator&lt;&lt;(<del>basic_ostream&lt;charT, traits&gt;</del> <ins>Ostream</ins>&amp;&amp; os, const T&amp; x);
</pre>
<blockquote>
<p>
1 <i>Effects:</i> <code>os &lt;&lt; x</code>
</p>
<p>
2 <i>Returns:</i> <code><ins>std::move(</ins>os<ins>)</ins></code>
</p>
<p><ins>
3 <i>Remarks:</i> This signature shall participate in overload resolution if
and only if <code>Ostream</code> is not an lvalue reference type and is derived from
<code>ios_base</code>.
</ins></p>
</blockquote>
</blockquote>
</blockquote>

<p><i>[2018-12-03, Ville comments]</i></p>

<p>
The implementation in libstdc++ doesn't require derivation from <code>ios_base</code>, it 
requires convertibility to <code>basic_istream/basic_ostream</code>. This has been found to be 
important to avoid regressions with existing stream wrappers.
<p/>
In libstdc++, the inserter/extractor also don't return a reference to the template parameter, 
they return a reference to the <code>basic_istream/basic_ostream</code> <em>specialization</em>
the template parameter converts to. This was done in order to try and be closer to the earlier 
specification's return type, which specified <code>basic_ostream&lt;charT, traits&gt;&amp;</code>
and <code>basic_istream&lt;charT, traits&gt;&amp;</code>. So we detected convertibility to
(a type convertible to) those, and returned the result of that conversion. That doesn't seem to 
be necessary, and probably bothers certain chaining cases. Based on recent experiments, it seems
that this return-type dance (as opposed to just returning what the p/r suggests) is unnecessary, 
and doesn't trigger any regressions.
</p>
<p><i>[2019-01-20 Reflector prioritization]</i></p>

<p>Set Priority to 2</p>

<p><strong>Previous resolution [SUPERSEDED]:</strong></p>
<blockquote class="note">
<p>This resolution is relative to N4750.</p>
<p>
Change 31.7.5.6 <a href="https://wg21.link/istream.rvalue">[istream.rvalue]</a> as follows:
</p>

<blockquote><pre>
template &lt;class <del>charT, class traits</del> <ins>Istream</ins>, class T&gt;
  <del>basic_istream&lt;charT, traits&gt;&amp;</del> <ins>Istream&amp;&amp;</ins>
  operator&gt;&gt;(<del>basic_istream&lt;charT, traits&gt;</del> <ins>Istream</ins>&amp;&amp; is, T&amp;&amp; x);
</pre>
<blockquote>
<p>
-1- <i>Effects:</i> Equivalent to:
</p>
<pre>
<code>is &gt;&gt; std::forward&lt;T&gt;(x)</code>
return <ins>std::move(</ins>is<ins>)</ins>;
</pre>
<p>-2- <i>Remarks:</i> This function shall not participate in overload
resolution unless the expression <code>is &gt;&gt; std::forward&lt;T&gt;(x)</code> is
well-formed<ins>, <code>Istream</code> is not an lvalue reference type, and
<code>Istream</code> is derived from <code>ios_base</code></ins>.</p>
</blockquote>
</blockquote>

<p>
Change 31.7.6.6 <a href="https://wg21.link/ostream.rvalue">[ostream.rvalue]</a>:
</p>

<blockquote><pre>
template &lt;class <del>charT, class traits</del> <ins>Ostream</ins>, class T&gt;
  <del>basic_ostream&lt;charT, traits&gt;&amp;</del> <ins>Ostream&amp;&amp;</ins>
  operator&lt;&lt;(<del>basic_ostream&lt;charT, traits&gt;</del> <ins>Ostream</ins>&amp;&amp; os, const T&amp; x);
</pre>
<blockquote>
<p>
-1- <i>Effects:</i> As if by: <code>os &lt;&lt; x;</code>
</p>
<p>
-2- <i>Returns:</i> <code><ins>std::move(</ins>os<ins>)</ins></code>
</p>
<p>
-3- <i>Remarks:</i> This signature shall not participate in overload resolution
unless the expression <code>os &lt;&lt; x</code> is well-formed<ins>,
<code>Ostream</code> is not an lvalue reference type, and <code>Ostream</code> is
derived from <code>ios_base</code></ins>.</p>
</blockquote>
</blockquote>
</blockquote>

<p><i>[2019-03-17; Daniel comments and provides updated wording]</i></p>

<p>
After discussion with Ville it turns out that the "derived from <code>ios_base</code>" approach works fine and
no breakages were found in regression tests. As result of that discussion the wording was rebased to the 
most recent working draft and the "overload resolution participation" wording was replaced by a 
corresponding <i>Constraints:</i> element.
</p>
<p><i>[2020-02 Status to Immediate on Friday morning in Prague.]</i></p>



<p id="res-1203"><b>Proposed resolution:</b></p>
<p>This wording is relative to <a href="https://wg21.link/n4810">N4810</a>.</p>

<ol>
<li><p>Change 31.7.5.6 <a href="https://wg21.link/istream.rvalue">[istream.rvalue]</a> as follows:</p>

<blockquote><pre>
template &lt;class <del>charT, class traits</del> <ins>Istream</ins>, class T&gt;
  <del>basic_istream&lt;charT, traits&gt;&amp;</del> <ins>Istream&amp;&amp;</ins>
  operator&gt;&gt;(<del>basic_istream&lt;charT, traits&gt;</del> <ins>Istream</ins>&amp;&amp; is, T&amp;&amp; x);
</pre>
<blockquote>
<p>
<ins>-?- <i>Constraints:</i> The expression <code>is &gt;&gt; std::forward&lt;T&gt;(x)</code> is
well-formed and <code>Istream</code> is publicly and unambiguously derived from <code>ios_base</code>.</ins>
<p/>
-1- <i>Effects:</i> Equivalent to:
</p>
<blockquote><pre>
<code>is &gt;&gt; std::forward&lt;T&gt;(x)</code>;
return <ins>std::move(</ins>is<ins>)</ins>;
</pre></blockquote>
<p><del>-2- <i>Remarks:</i> This function shall not participate in overload resolution 
unless the expression <code>is &gt;&gt; std::forward&lt;T&gt;(x)</code> is well-formed.</del></p>
</blockquote>
</blockquote>
</li>

<li>
<p>
Change 31.7.6.6 <a href="https://wg21.link/ostream.rvalue">[ostream.rvalue]</a>:
</p>

<blockquote><pre>
template &lt;class <del>charT, class traits</del> <ins>Ostream</ins>, class T&gt;
  <del>basic_ostream&lt;charT, traits&gt;&amp;</del> <ins>Ostream&amp;&amp;</ins>
  operator&lt;&lt;(<del>basic_ostream&lt;charT, traits&gt;</del> <ins>Ostream</ins>&amp;&amp; os, const T&amp; x);
</pre>
<blockquote>
<p>
<ins>-?- <i>Constraints:</i> The expression <code>os &lt;&lt; x</code> is well-formed and <code>Ostream</code> 
is publicly and unambiguously derived from <code>ios_base</code>.</ins>
<p/>
-1- <i>Effects:</i> As if by: <code>os &lt;&lt; x;</code>
<p/>
-2- <i>Returns:</i> <code><ins>std::move(</ins>os<ins>)</ins></code>.
<p/>
<del>-3- <i>Remarks:</i> This signature shall not participate in overload resolution
unless the expression <code>os &lt;&lt; x</code> is well-formed.</del></p>
</blockquote>
</blockquote>
</li>
</ol>






</body>
</html>
