Rob Stewart
On Mar 23, 2013, at 12:13 PM, Alexander Lamaison
wrote: Beman Dawes
writes: On Sat, Mar 16, 2013 at 12:54 PM, Alexander Lamaison
wrote: I'm manipulating Unix paths for use over SFTP, but doing so on Windows. For instance I might want to append "c" to the Unix path "/a/b".
path p("/a/b"); p /= "c"; cout << p.string();
In version 2 this would output "/a/b/c" but now it produces "/a/b\c". Why the breaking change?
IIRC, it was partially requests from users and partially the realization that most users want platform independent syntax but platform dependent semantics.
In that case I'd expect it to output "\a\b\c". I can't think of a reason why mixed slashes would ever be the right answer. It's the worst of both worlds.
You're expecting this line
path p("/a/b");
to parse your string into "a" / "b" when it merely stores the string as you gave it.
That's not true. It does parse the string and recognises "a" and "b" as separate segments of the path. If it didn't, iteration would return "a/b" followed by "c". I wrote a small program (included at the end) to prove this. Here is the output: Enter path: a/b string(): a/b generic_string(): a/b native(): a/b Segments: "a" "b" Enter path: a\b string(): a\b generic_string(): a/b native(): a\b Segments: "a" "b" Enter path: a/b\c string(): a/b\c generic_string(): a/b/c native(): a/b\c Segments: "a" "b" "c"
Otherwise, when you add this line
p /= "c";
you expect the previous separator to be used rather than the native separator it uses.
I expect the path to abstract over the separators used and, when asked for the path as a string, return something consistent. It doesn't matter if that means always using the native separator, as long as it doesn't use both.
But, the biggest issue is that the change wasn't documented. The docs make a big deal of the change from templated paths to a single path class, but make no mention of this, more significant, difference.
I can't imagine that Beman would reject a documentation patch.
I'll fix the documentation once I understand the reasoning.
If you would rather continue to use operator /= then change the output to
cout << p.generic_string();
I've since discovered this string/generic_string/native triplet. I don't think it's the right solution. string() should either return the generic string or the native string. What it returns at the moment is confusing and not very useful. Or is there a use-case I'm not seeing.
string() is returning the contents, as you instructed path to form it. Calling generic_string() means parse the contents and ensure all separators follow the generic syntax.
Constructing a path from "a/b" isn't an instruction to the library to construct a path with forward slashes. It's an instruction to create a path abstraction with two segments, the first "a" and the second "b". Separators shouldn't even come into it until a string representation of the path is requested, and the string conversion methods should make explicit what separator to use: generic or native.
To do what you want would require path to be modal.
I don't undestand what you mean here.
Marking it, in this case, to do everything in the generic format first would have given the behavior you wanted. However, there is no such modality. / appends with the native separator. Construction from a string, or appending one, merely stores the supplied string. When you want a specific format after mixing those operations, call generic_string() or native_string().
Again, this isn't true. / appends a segment. Separators are irrevant
to a path abstraction. In version 2 this was the case. v3 muddles
it by giving seperators extra significance.
Alex
#define BOOST_FILESYSTEM_VERSION 3
#include