Dundo
Dundo

Reputation: 764

filesystem::operator/ different behaviour in boost and std

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?

Edit:

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

Answers (1)

user14215102
user14215102

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

Related Questions