Boost logo

Boost :

Subject: Re: [boost] [filesystem] Request for comments on proposed relative() function
From: Gavin Lambert (gavinl_at_[hidden])
Date: 2014-05-13 22:00:25

On 9/05/2014 05:19, quoth Beman Dawes:
> *Returns: *An object of class path containing the first element of p that
> does not have a corresponding element in base, followed by the subsequent
> elements of p appended as if by path::operator/=.

Any chance of including in the docs some example inputs and outputs, or
test cases? I'm having trouble synchronising what I think this method
ought to be doing with what my understanding of this description
suggests. (Actually I have similar issues with most of the
Boost.Filesystem documentation -- possibly I just don't properly grok

Possibly I'm just interpreting it incorrectly, or I'm making an
incorrect assumption about the internals of path, but this description
does not sound correct.

> if (mm.first == p.end() || mm.second != base.end())
> {
> throw filesystem_error(
> "p does not begin with base, so can not be made relative to base",
> p, base,
> error_code(errc::invalid_argument, generic_category()));
> }

In the event that the provided path cannot be made relative to base,
isn't it more generically useful to return the original unmodified
absolute path? (ie. simply returning p instead of throwing, at least
when both paths are absolute.)

I'm assuming that the intended use case of this is to "minimise" a path
given a known working directory, and unrelated absolute paths are
already in their minimal form in that context.

Or another possibly useful output (as Daniel hinted at, though I don't
think he got the case right) would be to return a relative path using
dotdot syntax, so:

BOOST_TEST(fs::relative("/abc", "/abc/def") == path(".."));
BOOST_TEST(fs::relative("/ghi", "/abc/def") == path("../../ghi"));

This could be more useful in some cases (it bloats the path but makes it
more immune to being moved elsewhere). Maybe we even need both.

Although that brings up another question (which I'm not really familiar
enough with the "path" class internals to answer by looking at the
example implementation): is "base" intended to be assumed as a directory
name (which is how most filesystem "make relative" functions typically
work) or as a file name (which is how URL "make relative" works)? My
examples above assume the former, which seems consistent provided that
current_path() never returns a path with trailing directory separator
(unless the current path is the root).

On a peripherally related note, I find the following behaviour (on
Windows) surprising:

   fs::path("C:\\foo") / fs::path("C:\\bar") == fs::path("C:\\foo\\C:\\bar")

Shouldn't appending a root-path discard the prior path, like how
fs::absolute() works? (I assume this was intentional to simplify the
implementation, but I was hoping there would be something analogous to
Path.Combine from .NET, which can also return relative paths.)

Boost list run by bdawes at, gregod at, cpdaniel at, john at