Reputation: 764
I am trying to port from boost::filesystem
to std::filesystem
. During the process I encountered some code in which boost
and std
seems to behave in a different way.
The following code shows the behaviour:
#include <iostream>
#include <filesystem>
#include <boost/filesystem.hpp>
template<typename T>
void TestOperatorSlash()
{
const std::string foo = "Foo";
const std::string bar = "Bar";
const T start = "\\";
std::string sep;
sep += T::preferred_separator;
const auto output = start / (foo + bar) / sep;
std::cout << output << '\n';
}
int main(int argc, char** argv)
{
TestOperatorSlash<std::filesystem::path>();
TestOperatorSlash<boost::filesystem::path>();
}
The code gives in output:
"\\"
"\FooBar\"
The expected behaviour for me is the one of boost
, and I don't understand what happens with std::filesystem
.
Why do I get "\\"
?
Why is the behaviour of operator/
of path
different in boost
and std
?
After understanding the motivation of the behaviour of std::filesystem::operator/
and given the answer to this question, I decided to use the function path::relative_path()
for the second argument of operator/
when I have an absolute path.
In this way I can mimic the behaviour of boost::filesystem
.
So, for example:
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main(int argc, char** argv)
{
fs::path foo = "\\foo";
fs::path bar = "\\bar";
auto foobar0 = foo / bar; // Evaluates to \\bar
auto foobar1 = foo / bar.relative_path(); // Evaluates to \\foo\\bar
}
Upvotes: 6
Views: 464
Reputation:
Boost will merge redundant separators.
https://www.boost.org/doc/libs/1_68_0/libs/filesystem/doc/reference.html#path-appends
Appends path::preferred_separator to pathname, converting format and encoding if required ([path.arg.convert]), unless:
an added separator would be redundant, ...
Whereas std::filesystem sees a leading separator in the second argument of /
as an instruction to replace parts or all of the original path:
https://en.cppreference.com/w/cpp/filesystem/path/append
path("C:foo") / "/bar"; // yields "C:/bar" (removes relative path, then appends)
Did you want:
const auto output = start / (foo + bar) / "";
instead?
Upvotes: 4