使用 std::filesystem::path 在分隔符类型之间进行转换

pla*_*m95 7 c++ c++17

我正在处理涉及从路径加载文件的代码,该路径构造为从另一个文件加载的给定“基本”路径和辅助相对路径的串联。例如(以及我遇到问题的地方),基本路径是“assets/models/”,次要路径是“maps\map.png”。这两个字符串的直接连接给出了“assets/models/maps\map.png”。在 POSIX 系统上运行时,无法加载。到目前为止,我一直在通过将反斜杠替换为正斜杠来解决这个问题

std::replace( path.begin(), path.end(), '\\', '/' );

但我想用 C++17std::filesystem::path来代替。

的描述std::filesystem::path::make_preferred()表明它应该替换分隔符:

“将路径的通用格式视图中的所有目录分隔符转换为首选目录分隔符。例如,在 Windows 上,\ 是首选分隔符,路径 foo/bar 将转换为 foo\bar”

但是,在代码中实现时,它不会转换任何内容。我还验证了 std::filesystem::path::preferred_separator 符合预期 - '/'。

我误解了目的make_preferred()吗?还是我只是用错了?

这是不起作用的代码的简化版本(这不是实现的代码,但足够接近它):

const char * loadedPath = "maps\\map.png"
std::string loadedPathStr = std::string( loadedPath );
auto wPath = std::filesystem::path( loadedPathStr );
wPath = wPath.make_preferred();

basePath = std::filesystem::path( "./a/b/" );
auto totalPath = basePath / wPath;
auto wStr = totalPath.generic_string();
std::cout << wStr << std::endl;
Run Code Online (Sandbox Code Playgroud)

这输出“./a/b/maps\\map.png”

在调试实现的代码时,它看起来像wPath优化了;没有办法检查它。

奇怪的是,当我编译并运行这个独立的测试程序时,它按预期工作:

int main(){
   assert( std::filesystem::path::preferred_separator == '/' );            
   const char * cPath = "maps\\map.png";
   std::string path = std::string( cPath );
   auto wPath = std::filesystem::path( path );
   wPath = wPath.make_preferred();
   std::string wStr = wPath.generic_string();
   std::cout << wStr << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

这将输出“maps/map.png”。我读不懂。这也会输出不正确的值。

有谁知道这里发生了什么?

编辑: 尝试用 clang 编译(之前使用 gcc),它按预期工作(分隔符被转换)。忽略这一点,在重新编译时出错。

我在 Linux 上运行它,并且路径存在。

eer*_*ika 5

我误解了目的make_preferred()吗?

不完全,但巧妙地是。目录分隔符(通用格式)是首选分隔符或备用分隔符:/。在首选分隔符为/(例如 POSIX)的系统上,目录分隔符仅为/. 在这样的系统make_preferred上不会修改路径,这就解释了为什么它会被完全优化。

用正斜杠替换反斜杠的最简单方法是std::replace. 但是,请注意反斜杠是 POSIX 中文件名中的有效字符,因此此类转换可能会破坏使用它的文件名的使用。