<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 3430: std::fstream &amp; co. should be constructible from string_view</title>
<meta property="og:title" content="Issue 3430: std::fstream &amp; co. should be constructible from string_view">
<meta property="og:description" content="C++ library issue. Status: C++23">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue3430.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++23">C++23</a> status.</em></p>
<h3 id="3430"><a href="lwg-defects.html#3430">3430</a>. <code>std::fstream</code> &amp; co. should be constructible from <code>string_view</code></h3>
<p><b>Section:</b> 31.10.1 <a href="https://wg21.link/fstream.syn">[fstream.syn]</a> <b>Status:</b> <a href="lwg-active.html#C++23">C++23</a>
 <b>Submitter:</b> Jonathan Wakely <b>Opened:</b> 2020-04-15 <b>Last modified:</b> 2023-11-22</p>
<p><b>Priority: </b>3
</p>
<p><b>View all issues with</b> <a href="lwg-status.html#C++23">C++23</a> status.</p>
<p><b>Discussion:</b></p>
<p>
We have:
</p>
<blockquote><pre>
basic_fstream(const char*, openmode);
basic_fstream(const filesystem::path::value_type*, openmode); // wide systems only
basic_fstream(const string&amp;, openmode);
basic_fstream(const filesystem::path&amp;, openmode);
</pre></blockquote>
<p>
I think the omission of a <code>string_view</code> overload was intentional, because the underlying OS call 
(such as <code>fopen</code>) needs a NTBS. We wanted the allocation required to turn a <code>string_view</code> 
into an NTBS to be explicitly requested by the user. But then we added the <code>path</code> overload, 
which is callable with a <code>string_view</code>. Converting to a <code>path</code> is more expensive than 
converting to <code>std::string</code>, because a path has to <em>at least</em> construct a <code>basic_string</code>, 
and potentially also does an encoding conversion, parses the path, and potentially allocates a sequence 
of <code>path</code> objects for the path components.
<p/>
This means the simpler, more obvious code is slower and uses more memory:
</p>
<blockquote><pre>
string_view sv = "foo.txt";
fstream f1(sv); // bad
fstream f2(string(sv)); // good
</pre></blockquote>
<p>
We should just allow passing a <code>string_view</code> directly, since it already compiles but 
doesn't do what anybody expects or wants.
<p/>
Even with a <code>string_view</code> overload, passing types like <code>const char16_t*</code> or <code>u32string_view</code> 
will still implicitly convert to <code>filesystem::path</code>, but that seems reasonable. In those cases the 
encoding conversion is necessary. For Windows we support construction from <code>const wchar_t*</code> but not 
from <code>wstring</code> or <code>wstring_view</code>, which means those types will convert to <code>filesystem::path</code>. 
That seems suboptimal, so we might also want to add <code>wstring</code> and <code>wstring_view</code> overloads for 
"wide systems only", as per 31.10.1 <a href="https://wg21.link/fstream.syn">[fstream.syn]</a> p3.
<p/>
Daniel:
<p/>
LWG <a href="lwg-active.html#2883" title="The standard library should provide string_view parameters instead or in addition for functions 
      defined with char const * or string const &amp; as parameter types. (Status: LEWG)">2883</a><sup><a href="https://cplusplus.github.io/LWG/issue2883" title="Latest snapshot">(i)</a></sup> has a more general view on that but does not consider potential cost differences 
in the presence of <code>path</code> overloads (Which didn't exist at this point yet).
</p>

<p><i>[2020-05-09; Reflector prioritization]</i></p>

<p>
Set priority to 3 after reflector discussions.
</p>

<p><i>[2020-08-10; Jonathan comments]</i></p>

<p>
An alternative fix would be to retain the original design and not allow
construction from a <code>string_view</code>. The <code>path</code> parameters
could be changed to template parameters which are constrained to be exactly
<code>path</code>, and not things like <code>string_view</code> which can convert
to <code>path</code>.
</p>

<p><i>[2020-08-21; Issue processing telecon: send to LEWG]</i></p>

<p>
Just adding support for <code>string_view</code> doesn't prevent expensive
conversions from other types that convert to <code>path</code>.
Preference for avoiding all expensive implicit conversions to <code>path</code>,
maybe via abbreviated function templates:
<pre>
basic_fstream(same_as&lt;filesystem::path&gt; auto const&amp;, openmode);
</pre>
</p>
<p>
It's possible <code>path_view</code> will provide a better option at some point.
</p>
<p>
It was noted that <a href="lwg-defects.html#2676" title="Provide filesystem::path overloads for File-based streams (Status: C++17)">2676</a><sup><a href="https://cplusplus.github.io/LWG/issue2676" title="Latest snapshot">(i)</a></sup> did intentionally allow conversions
from "strings of character types <code>wchar_t</code>, <code>char16_t</code>,
and <code>char32_t</code>". Those conversions don't need to be implicit
for that to be supported.
</p>

<p><i>[2020-09-11; Tomasz comments and provides wording]</i></p>

<p>
During the <a href="https://wiki.edg.com/bin/view/Wg21summer2020/LWG3430">LEWG 2020-08-24 telecon</a> 
the LEWG provided following guidance on the issue:
</p>
<blockquote style="border-left: 3px solid #ccc;padding-left: 15px;">
<p>
We took one poll (exact wording in the notes) to constrain the constructor which takes 
<code>filesystem::path</code> to only take <code>filesystem::path</code> and not things convertible to it, 
but only 9 out of 26 people present actually voted. Our interpretation: LWG should go ahead with 
making this change. There is still plenty of time for someone who hasn't yet commented on this to 
bring it up even if it is in a tentatively ready state. It would be nice to see a paper to address 
the problem of the templated path constructor, but no one has yet volunteered to do so. 
Note: the issue description is now a misnomer, as adding a <code>string_view</code> constructor 
is no longer being considered at this time.
</p>
</blockquote>
<p>
The proposed P/R  follows original LWG proposal and makes the <code>path</code> constructor of the 
<code>basic_*fstreams</code> "<code>explicit</code>". To adhere to current policy, we refrain from use of 
requires clauses and abbreviated function syntax, and introduce a <i>Constraints</i> element.
</p>

<p><i>[2021-05-21; Reflector poll]</i></p>

<p>
Set status to Tentatively Ready after seven votes in favour during reflector poll.
</p>

<p><i>[2021-06-07 Approved at June 2021 virtual plenary. Status changed: Voting &rarr; WP.]</i></p>



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

<ol>
<li><p>Modify 31.10.4 <a href="https://wg21.link/ifstream">[ifstream]</a>, class template <code>basic_ifstream</code> synopsis, as indicated:</p>

<blockquote>
<pre>
[&hellip;]
explicit basic_ifstream(const string&amp; s,
                        ios_base::openmode mode = ios_base::in);
<ins>template&lt;class T&gt;</ins>
explicit basic_ifstream(const <del>filesystem::path</del><ins>T</ins>&amp; s,
                        ios_base::openmode mode = ios_base::in);
[&hellip;]
</pre>
</blockquote>
</li>

<li><p>Modify 31.10.4.2 <a href="https://wg21.link/ifstream.cons">[ifstream.cons]</a> as indicated:</p>

<blockquote>
<pre>
explicit basic_ifstream(const string&amp; s,
                        ios_base::openmode mode = ios_base::in);
</pre>
<blockquote>
<p>
<ins>-?- <i>Effects:</i> Equivalent to: <code>basic_ifstream(s.c_str(), mode)</code>.</ins>
</p>
</blockquote>
<pre>
<ins>template&lt;class T&gt;</ins>
explicit basic_ifstream(const <del>filesystem::path</del><ins>T</ins>&amp; s,
                        ios_base::openmode mode = ios_base::in);
</pre>
<blockquote>
<p>
<ins>-?- <i>Constraints:</i> <code>is_same_v&lt;T, filesystem::path&gt;</code> is <code>true</code>.</ins>
<p/>
-3- <i>Effects:</i> Equivalent to: <code>basic_ifstream(s.c_str(), mode)</code>.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Modify 31.10.5 <a href="https://wg21.link/ofstream">[ofstream]</a>, class template <code>basic_ofstream</code> synopsis, as indicated:</p>

<blockquote>
<pre>
[&hellip;]
explicit basic_ofstream(const string&amp; s,
                        ios_base::openmode mode = ios_base::out);
<ins>template&lt;class T&gt;</ins>
explicit basic_ofstream(const <del>filesystem::path</del><ins>T</ins>&amp; s,
                        ios_base::openmode mode = ios_base::out);
[&hellip;]
</pre>
</blockquote>
</li>

<li><p>Modify 31.10.5.2 <a href="https://wg21.link/ofstream.cons">[ofstream.cons]</a> as indicated:</p>

<blockquote>
<pre>
explicit basic_ofstream(const string&amp; s,
                        ios_base::openmode mode = ios_base::out);
</pre>
<blockquote>
<p>
<ins>-?- <i>Effects:</i> Equivalent to: <code>basic_ofstream(s.c_str(), mode)</code>.</ins>
</p>
</blockquote>
<pre>
<ins>template&lt;class T&gt;</ins>
explicit basic_ofstream(const <del>filesystem::path</del><ins>T</ins>&amp; s,
                        ios_base::openmode mode = ios_base::out);
</pre>
<blockquote>
<p>
<ins>-?- <i>Constraints:</i> <code>is_same_v&lt;T, filesystem::path&gt;</code> is <code>true</code>.</ins>
<p/>
-3- <i>Effects:</i> Equivalent to: <code>basic_ofstream(s.c_str(), mode)</code>.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Modify 31.10.6 <a href="https://wg21.link/fstream">[fstream]</a>, class template <code>basic_fstream</code> synopsis, as indicated:</p>

<blockquote>
<pre>
[&hellip;]
explicit basic_fstream(
  const string&amp; s,
  ios_base::openmode mode = ios_base::in | ios_base::out);
<ins>template&lt;class T&gt;</ins>
explicit basic_fstream(
  const <del>filesystem::path</del><ins>T</ins>&amp; s,
  ios_base::openmode mode = ios_base::in | ios_base::out);
[&hellip;]
</pre>
</blockquote>
</li>

<li><p>Modify 31.10.6.2 <a href="https://wg21.link/fstream.cons">[fstream.cons]</a> as indicated:</p>

<blockquote>
<pre>
explicit basic_fstream(
  const string&amp; s,
  ios_base::openmode mode = ios_base::in | ios_base::out);
</pre>
<blockquote>
<p>
<ins>-?- <i>Effects:</i> Equivalent to: <code>basic_fstream(s.c_str(), mode)</code>.</ins>
</p>
</blockquote>
<pre>
<ins>template&lt;class T&gt;</ins>
explicit basic_fstream(
  const <del>filesystem::path</del><ins>T</ins>&amp; s,
  ios_base::openmode mode = ios_base::in | ios_base::out);
</pre>
<blockquote>
<p>
<ins>-?- <i>Constraints:</i> <code>is_same_v&lt;T, filesystem::path&gt;</code> is <code>true</code>.</ins>
<p/>
-3- <i>Effects:</i> Equivalent to: <code>basic_fstream(s.c_str(), mode)</code>.
</p>
</blockquote>
</blockquote>
</li>

</ol>




</body>
</html>
