我可以确认,这不是先决条件问题,而且我认为 GCC 是正确的,但我的猜测是,在这一点上澄清标准会有所帮助。
长期以来,使用尾随分隔符标记目录是很常见的使用模式,以将它们与文件区分开来。如果要创建的路径在调用之前不存在,并且由于调用而在调用之后存在,我希望实现std::filesystem::create_directories
返回 true。
让我们稍微扩展一下这个例子:
#include <filesystem>
#include <iostream>
#include <system_error>
int main() {
std::error_code ec;
std::cout << std::boolalpha << std::filesystem::exists("a/b/c/") << "/";
std::cout << std::filesystem::create_directories("a/b/c/", ec) << "/";
std::cout << !!ec << "/" << std::filesystem::exists("a/b/c/");
}
现在我们可以使用godbolt了:https ://godbolt.org/z/5883uY
正如我们所期望的那样,它显示为 GCC/libstdc++ false/true/false/true
,它不存在,它是由create_directories
调用创建的,没有错误,之后它就存在了。
现在 clang/libc++ 结果false/false/false/true
,所以它不存在,它告诉我们它没有创建它,但是它确实创建了它,没有错误,我们在调用后证明了。
查看 MSVC stl 的 github 版本,它看起来像调用CreateDirectoryW
:a
,a\b
,a\b\c
和 finally a\b\c\
,最后一个报告ERROR_ALREADY_EXISTS
,这导致false
我们似乎没有做任何事情的返回,但我认为这是一个实现细节渗出功能。我的猜测是,Clang 代码的工作方式类似,但我还没有检查 libc++ 源代码。
标准内容如下:“返回:如果创建了新目录,则返回 true,否则返回 false。如果发生错误,带有参数 ec 的签名将返回 false。”
因此,标准想要创建一个目录true
,而不是最后一个目录,并且对于ec变体发出错误信号,但 clang 告诉我们没有。false
ec
我可能仍然是错的,因为我不在任何 WG 中,但我的结论是:GCC 是正确的,它似乎是 MSVC 和 Clang 中的一个错误。
因为我在验证我自己的实现时已经收集了实现之间的差异,所以如果可以的话,我会“高兴地”将这个添加到我的集合中。
更新:我刚刚挖掘了其他来源,Clang/libc++ 使用基于递归parent_path()
的机制,最终导致与 MSVC 相同的序列,其中最后一个::mkdir("a/b/c/")
前面是 a::mkdir("a/b/c")
所以它报告错误,因为它假设它没有创建目录。