<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2664: operator/ (and other append) semantics not useful if argument has root</title>
<meta property="og:title" content="Issue 2664: operator/ (and other append) semantics not useful if argument has root">
<meta property="og:description" content="C++ library issue. Status: C++17">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2664.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++17">C++17</a> status.</em></p>
<h3 id="2664"><a href="lwg-defects.html#2664">2664</a>. <code>operator/</code> (and other append) semantics not useful if argument has root</h3>
<p><b>Section:</b> 31.12.6.5.3 <a href="https://wg21.link/fs.path.append">[fs.path.append]</a>, 31.12.6.8 <a href="https://wg21.link/fs.path.nonmember">[fs.path.nonmember]</a> <b>Status:</b> <a href="lwg-active.html#C++17">C++17</a>
 <b>Submitter:</b> Peter Dimov <b>Opened:</b> 2014-05-30 <b>Last modified:</b> 2017-07-30</p>
<p><b>Priority: </b>2
</p>
<p><b>View all other</b> <a href="lwg-index.html#fs.path.append">issues</a> in [fs.path.append].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#C++17">C++17</a> status.</p>
<p><b>Discussion:</b></p>
<p>
  In a recent discussion on the Boost developers mailing list, the semantics of <code>operator /</code>
  and other append operations were questioned:
<p/>
In brief, currently <code>p1 / p2</code> is required to concatenate the
  lexical representation of <code>p1</code> and <code>p2</code>, inserting a
  preferred separator as needed.
<p/>
This means that, for example, <code>&quot;c:\x&quot; / &quot;d:\y&quot;</code> gives <code>
    &quot;c:\x\d:\y&quot;</code>, and that <code>&quot;c:\x&quot; / &quot;\\server\share&quot;</code>
    gives <code>&quot;c:\x\\server\share&quot;</code>. This is rarely, if ever, useful.
<p/>
An alternative interpretation of <code>p1 / p2</code> could be that it yields a
  path that is the approximation of what <code>p2</code> would mean if interpreted
  in an environment in which <code>p1</code> is the starting directory. 
  Under this interpretation, <code>&quot;c:\x&quot; / &quot;d:\y&quot;</code> gives <code>&quot;d:\y&quot;</code>,
  which is more likely to match what was intended.
<p/>
I am not saying that this second interpretation is the right one, but I do say
  that we have reasons to suspect that the first one (lexical concatenation using
  a separator) may not be entirely correct.
  This leads me to think that the behavior of <code>p1 / p2</code>, when <code>p2</code>
  has a root, needs to be left implementation-defined, so that implementations are
  not required to do the wrong thing, as above.
<p/>
This change will not affect the ordinary use case in which <code>p2</code> is a
  relative, root-less, path.
</p>  
<p><i>[17 Jun 2014 Rapperswil LWG will investigate issue at a subsequent meeting.]</i></p>


<p><i>[2016-02, Jacksonville]</i></p>

<p>Beman to provide wording.</p>

<p><i>[2016-06-13, Beman provides wording and rationale]</i></p>

<p>
<b>Rationale:</b> The purpose of the append operations is to provide a simple concatenation facility for users 
wishing to extend a path by appending one or more additional elements, and to do so without worrying about the 
details of when a separator is needed. In that context it makes no sense to provide an argument that has a 
<i>root-name</i>. The simplest solution is simply to require <code>!p.has_root_name()</code>.
The other suggested solutions IMO twist the functions into something harder to reason about
yet any advantages for users are purely speculative. The concatenation functions can
be used instead for corner cases.
</p>

<p><i>[<b>Apr 2016 Issue updated to address the C++ Working Paper. Previously addressed File System TS</b>]</i></p>
 

<p><i>[2016-07-03, Daniel comments]</i></p>

<p>
The same wording area is touched by LWG <a href="lwg-defects.html#2732" title="Questionable specification of path::operator/= and path::append (Status: C++17)">2732</a><sup><a href="https://cplusplus.github.io/LWG/issue2732" title="Latest snapshot">(i)</a></sup>.
</p>

<p><strong>Previous resolution [SUPERSEDED]:</strong></p>
<blockquote class="note">
<p>This wording is relative to N4594.</p>
<ol>
<li><p><i>Change 31.12.6.5.3 <a href="https://wg21.link/fs.path.append">[fs.path.append]</a> path appends as indicated:</i></p>

<blockquote>
<code>path&amp; operator/=(const path&amp; p);</code>
<blockquote>
  <p><ins>-?- <i>Requires:</i> <code>!p.has_root_name()</code>.</ins></p>
  <p>-2- <i>Effects:</i> Appends <code>path::preferred_separator</code> to <code>pathname</code> unless:</p>
  <ul>
  <li><p>an added <i>directory-separator</i> would be redundant, or</p></li>
  <li><p>an added <i>directory-separator</i> would change a relative path to an absolute path 
  [<i>Note:</i> An empty path is relative. &mdash; <i>end note</i>], or</p></li>
  <li><p><code>p.empty()</code> is <code>true</code>, or</p></li>
  <li><p><code>*p.native().cbegin()</code> is a <i>directory-separator</i>.</p></li>
  </ul>
  <p>Then appends <code>p.native()</code> to <code>pathname</code>.</p>
  <p>-3- <i>Returns:</i> <code>*this</code>.</p>
</blockquote>
<code>template &lt;class Source&gt;<br/>
&nbsp; path&amp; operator/=(const Source&amp; source);<br/>
template &lt;class Source&gt;<br/>
&nbsp; path&amp; append(const Source&amp; source);<br/>
template &lt;class InputIterator&gt;<br/>
&nbsp; path&amp; append(InputIterator first, InputIterator last);</code>
<blockquote>
<p>
<ins>-?- <i>Requires:</i> <code>!source.has_root_name()</code> or
<code>!*first.has_root_name()</code>, respectively.</ins>
<p/>
-4- <i>Effects:</i> Appends <code>path::preferred_separator</code> to <code>pathname</code>,
converting format and encoding if required (31.12.6.3 <a href="https://wg21.link/fs.path.cvt">[fs.path.cvt]</a>), unless:
</p>
<ul>
  <li><p>an added <i>directory-separator</i> would be redundant, or</p></li>
  <li><p>an added <i>directory-separator</i> would change a relative path to an absolute path, or</p></li>
  <li><p><code>source.empty()</code> is <code>true</code>, or</p></li>
  <li><p><code>*source.native().cbegin()</code> is a <i>directory-separator</i>.</p></li>
</ul>
<p>
Then appends the effective range of <code>source</code> (31.12.6.4 <a href="https://wg21.link/fs.path.req">[fs.path.req]</a>) or the range
<code>[first, last)</code> to <code>pathname</code>, converting format and encoding if required (31.12.6.3 <a href="https://wg21.link/fs.path.cvt">[fs.path.cvt]</a>).
<p/>
-5- <i>Returns:</i> <code>*this</code>.
</p>
</blockquote>
</blockquote>
</li>

<li><p><i>Change 31.12.6.8 <a href="https://wg21.link/fs.path.nonmember">[fs.path.nonmember]</a> path non-member functions as indicated:</i></p>

<blockquote>
<code>path operator/(const path&amp; lhs, const path&amp; rhs);</code>
  <blockquote>
  <p><ins>-?- <i>Requires:</i> <code>!rhs.has_root_name()</code>.</ins></p>
  <p>-13- <i>Returns:</i> <code>path(lhs) /= rhs</code>.</p>
  </blockquote>
</blockquote>
</li>
</ol>
</blockquote>

<p><i>[2016-08-03 Chicago]</i></p>

<p>After discussion on <a href="lwg-defects.html#2732" title="Questionable specification of path::operator/= and path::append (Status: C++17)">2732</a><sup><a href="https://cplusplus.github.io/LWG/issue2732" title="Latest snapshot">(i)</a></sup>, it was determined that the PR for that issue should be
applied to this issue before it is accepted. That PR changes all the path appends to go through
operator/=, so only one requires element remains necessary.</p>
<p>Fri AM: Moved to Tentatively Ready</p>


<p id="res-2664"><b>Proposed resolution:</b></p>
<p>This wording is relative to N4606, and assumes that the PR for <a href="lwg-defects.html#2732" title="Questionable specification of path::operator/= and path::append (Status: C++17)">2732</a><sup><a href="https://cplusplus.github.io/LWG/issue2732" title="Latest snapshot">(i)</a></sup> is applied.</p>
<ol>
<li>Change 31.12.6.5.3 <a href="https://wg21.link/fs.path.append">[fs.path.append]</a> as indicated:
<pre>path&amp; operator/=(const path&amp; p);</pre>
<blockquote>
  <p><ins>-?- <i>Requires:</i> <code>!p.has_root_name()</code>.</ins></p>
  <p>-2- <i>Effects:</i> Appends <code>path::preferred_separator</code> to <code>pathname</code> unless:</p>
  <ol style="list-style-type: none">
  <li>&mdash; an added <i>directory-separator</i> would be redundant, or</li>
  <li>&mdash; an added <i>directory-separator</i> would change a relative path to an absolute path
  [<i>Note:</i> An empty path is relative. &mdash; <i>end note</i>], or</li>
  <li>&mdash; <code>p.empty()</code> is <code>true</code>, or</li>
  <li>&mdash; <code>*p.native().cbegin()</code> is a <i>directory-separator</i>.</li>
  </ol>
  <p>Then appends <code>p.native()</code> to <code>pathname</code>.</p>
  <p>-3- <i>Returns:</i> <code>*this</code>.</p>
</blockquote>
</li>
<li>Change 31.12.6.8 <a href="https://wg21.link/fs.path.nonmember">[fs.path.nonmember]</a> p13 as indicated:
<pre>path operator/(const path&amp; lhs, const path&amp; rhs);</pre>
<blockquote>
<p>-13- <em><del>Returns</del><ins>Effects</ins>:</em> <ins>Equivalent to </ins><code>
<ins>return </ins>path(lhs) /= rhs;</code>.</p>
</blockquote>
</li>
</ol>





</body>
</html>
