
On Sat, Aug 21, 2004 at 08:30:43AM +0100, Keith Burton wrote:
And the following will fail (assertion?): std::cout << p4.string() // Not allowed because p4 is native (complete).
Why should this fail ? It seems an unnecessary restriction
Perhaps more extension of the API is needed. There is a mixup up of two different types of 'native'. 'native' means "works only on the OS that the application is currently running on". But still, there two distinct ways that a path can fail to be portable: 1) It can contain characters that are not portable, or use a format that is not portable. 2) The root base (an explicit, complete, directory) is well, explicit. The internal 'native' state that I introduced marks the latter, assuming that any complete path is automatically not portable because the 'root' part of any path is simply not portable. But, as I said before, this 'native' wouldn't change the format of the string returned by 'string()'. And now, as you noted, I suddenly propose to also trip on the *usage* of 'string()' when this 'native' flags (with the second meaning) is set! I agree that this is a duality and some refinement might be better. However, just plain allowing it seems wrong. If a programmer uses a complete path, then it is per definition not portable (point 2) and therefore marked internally as a 'native' path of the second kind. Then when a programmer converts the path to a std::string, he should show somehow that he is aware of the fact that this is not portable. The idea was to reserve path::string() for portable strings, that can be used regardless of the OS. But well, you are right if you say that it might be needed, because there is also this thing 'representation'. A programmer might need the 'canonical' representation of a path - having nothing else then that path. The current boost::filesystem just allows one to 'store' all kind of paths that are out there, and gards point 1), only. If a path contains a "c:/Program Files/My Documents", then string() will return that, and native_directory_string() will return "C:\Program Files\My Documents". I can imagine that that is not wanted in some cases. The most clean, logical, way to improve this would be to have a way to convert complete paths back to relative paths, and then use string(). But there are inprinciple many relative paths (one for each directory it contains) so I don't like the conversion (removing an explicit root base should be possible though). A straight forward shortcircuit of this problem would be to introduce the same function but with a different name. Like fs::path::complete_string, which would be allowed on complete paths and return then what string() returns now. That brings me to a new idea: why not have two different _types_? fs::relative_path and fs::native_path. Then, a program that uses code that you considered problematic turns into something like this: #ifdef __CYGWIN__ fs::native_path rootbase(get_cygwin_root()); #else // ... #endif fs::relative_path tmpdir(rootbase); tmpdir = "tmp"; fs::relative_path session_socket(tmpdir); session_socket = fs::relative_path("screen") / username() / "s0"; std::cout << session_socket.string() << std::endl; // Prints "screen/carlo/s0". std::cout << session_socket.native_file_string() << std::endl; // Prints "[screen/carlo]:s0" on VMS. fs::native_path completed_session_socket(session_socket); std::cout << completed_session_socket.string() << std::endl; // Prints "c:/cygwin/tmp/screen/carlo/s0" on cygwin. std::cout << completed_session_socket.native_directory_string() << std::endl; // Prints "C:\cygwin\tmp\screen\carlo\s0" on cygwin. In this senario I do not have a problem with allowing 'string()' to be called, because having a separate type for complete path's is enough clarity for me. Note that in this case: fs::relative_path foo; // Uses fs::current_path() as root base. fs::complete(foo) // returns fs::current_path() / foo. fs::complete(foo, tmp) // returns tmp / foo. The first parameter of fs::complete must be a relative_path and the second a native_path.