Title
operator/ (and other append) semantics not useful if argument has root
Status
c++17
Section
[fs.path.append] [fs.path.nonmember]
Submitter
Peter Dimov

Created on 2014-05-30.00:00:00 last changed 90 months ago

Messages

Date: 2017-03-19.19:35:20

Proposed resolution:

This wording is relative to N4606, and assumes that the PR for 2732 is applied.

  1. Change [fs.path.append] as indicated:
    path& operator/=(const path& p);

    -?- Requires: !p.has_root_name().

    -2- Effects: Appends path::preferred_separator to pathname unless:

    1. — an added directory-separator would be redundant, or
    2. — an added directory-separator would change a relative path to an absolute path [Note: An empty path is relative. — end note], or
    3. p.empty() is true, or
    4. *p.native().cbegin() is a directory-separator.

    Then appends p.native() to pathname.

    -3- Returns: *this.

  2. Change [fs.path.nonmember] p13 as indicated:
    path operator/(const path& lhs, const path& rhs);

    -13- ReturnsEffects: Equivalent to return path(lhs) /= rhs;.

Date: 2016-08-03.00:00:00

[ 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

Date: 2016-07-15.00:00:00

[ 2016-07-03, Daniel comments ]

The same wording area is touched by LWG 2732.

Previous resolution [SUPERSEDED]:

This wording is relative to N4594.

  1. Change [fs.path.append] path appends as indicated:

    path& operator/=(const path& p);

    -?- Requires: !p.has_root_name().

    -2- Effects: Appends path::preferred_separator to pathname 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() is true, or

    • *p.native().cbegin() is a directory-separator.

    Then appends p.native() to pathname.

    -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: !source.has_root_name() or !*first.has_root_name(), respectively.

    -4- Effects: Appends path::preferred_separator to pathname, converting format and encoding if required ([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() is true, or

    • *source.native().cbegin() is a directory-separator.

    Then appends the effective range of source ([fs.path.req]) or the range [first, last) to pathname, converting format and encoding if required ([fs.path.cvt]).

    -5- Returns: *this.

  2. Change [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.

Date: 2016-06-14.10:32:15

[ Apr 2016 Issue updated to address the C++ Working Paper. Previously addressed File System TS ]

Date: 2016-06-15.00:00:00

[ 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.

Date: 2016-03-07.04:46:57

[ 2016-02, Jacksonville ]

Beman to provide wording.

Date: 2016-01-28.01:00:35

[ 17 Jun 2014 Rapperswil LWG will investigate issue at a subsequent meeting. ]

Date: 2016-04-10.22:23:37

In a recent discussion on the Boost developers mailing list, the semantics of operator / and other append operations were questioned:

In brief, currently 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.

History
Date User Action Args
2017-07-30 20:15:43adminsetstatus: wp -> c++17
2016-11-14 03:59:28adminsetstatus: pending -> wp
2016-11-14 03:55:22adminsetstatus: ready -> pending
2016-08-06 20:44:18adminsetstatus: new -> ready
2016-08-03 20:47:51adminsetmessages: + msg8374
2016-07-03 12:47:29adminsetmessages: + msg8224
2016-06-14 10:32:15adminsetmessages: + msg8174
2016-06-14 10:32:15adminsetmessages: + msg8173
2016-04-10 22:23:37adminsetmessages: + msg8038
2016-03-07 04:46:57adminsetmessages: + msg8007
2016-01-28 01:00:35adminsetmessages: + msg7917
2014-05-30 00:00:00admincreate