operator/
(and other append) semantics not useful if argument has rootSection: 31.12.6.5.3 [fs.path.append], 31.12.6.8 [fs.path.nonmember] Status: C++17 Submitter: Peter Dimov Opened: 2014-05-30 Last modified: 2017-07-30
Priority: 2
View all other issues in [fs.path.append].
View all issues with C++17 status.
Discussion:
In a recent discussion on the Boost developers mailing list, the semantics of operator /
and other append operations were questioned:
p1 / p2
is required to concatenate the
lexical representation of p1
and p2
, inserting a
preferred separator as needed.
This means that, for example, "c:\x" / "d:\y"
gives
"c:\x\d:\y"
, and that "c:\x" / "\\server\share"
gives "c:\x\\server\share"
. This is rarely, if ever, useful.
An alternative interpretation of p1 / p2
could be that it yields a
path that is the approximation of what p2
would mean if interpreted
in an environment in which p1
is the starting directory.
Under this interpretation, "c:\x" / "d:\y"
gives "d:\y"
,
which is more likely to match what was intended.
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 p1 / p2
, when p2
has a root, needs to be left implementation-defined, so that implementations are
not required to do the wrong thing, as above.
This change will not affect the ordinary use case in which p2
is a
relative, root-less, path.
[17 Jun 2014 Rapperswil LWG will investigate issue at a subsequent meeting.]
[2016-02, Jacksonville]
Beman to provide wording.
[2016-06-13, Beman provides wording and rationale]
Rationale: 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
root-name. The simplest solution is simply to require !p.has_root_name()
.
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.
[Apr 2016 Issue updated to address the C++ Working Paper. Previously addressed File System TS]
[2016-07-03, Daniel comments]
The same wording area is touched by LWG 2732.
Previous resolution [SUPERSEDED]:
This wording is relative to N4594.
Change 31.12.6.5.3 [fs.path.append] path appends as indicated:
path& operator/=(const path& p);
-?- Requires:
!p.has_root_name()
.-2- Effects: Appends
path::preferred_separator
topathname
unless:
an added directory-separator would be redundant, or
an added directory-separator would change a relative path to an absolute path [Note: An empty path is relative. — end note], or
p.empty()
istrue
, or
*p.native().cbegin()
is a directory-separator.Then appends
p.native()
topathname
.-3- Returns:
*this
.template <class Source>
path& operator/=(const Source& source);
template <class Source>
path& append(const Source& source);
template <class InputIterator>
path& append(InputIterator first, InputIterator last);-?- Requires:
-4- Effects: Appends!source.has_root_name()
or!*first.has_root_name()
, respectively.path::preferred_separator
topathname
, converting format and encoding if required (31.12.6.3 [fs.path.cvt]), unless:
an added directory-separator would be redundant, or
an added directory-separator would change a relative path to an absolute path, or
source.empty()
istrue
, or
*source.native().cbegin()
is a directory-separator.Then appends the effective range of
-5- Returns:source
(31.12.6.4 [fs.path.req]) or the range[first, last)
topathname
, converting format and encoding if required (31.12.6.3 [fs.path.cvt]).*this
.Change 31.12.6.8 [fs.path.nonmember] path non-member functions as indicated:
path operator/(const path& lhs, const path& rhs);
-?- Requires:
!rhs.has_root_name()
.-13- Returns:
path(lhs) /= rhs
.
[2016-08-03 Chicago]
After discussion on 2732, 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.
Fri AM: Moved to Tentatively Ready
Proposed resolution:
This wording is relative to N4606, and assumes that the PR for 2732 is applied.
path& operator/=(const path& p);
-?- Requires:
!p.has_root_name()
.-2- Effects: Appends
path::preferred_separator
topathname
unless:
- — an added directory-separator would be redundant, or
- — an added directory-separator would change a relative path to an absolute path [Note: An empty path is relative. — end note], or
- —
p.empty()
istrue
, or- —
*p.native().cbegin()
is a directory-separator.Then appends
p.native()
topathname
.-3- Returns:
*this
.
path operator/(const path& lhs, const path& rhs);
-13-
ReturnsEffects: Equivalent toreturn path(lhs) /= rhs;
.