`std :: filesystem :: path`没有标准哈希值吗?

Edw*_*ard 4 c++ hash c++17

我有一个简单的程序,旨在存储一组C++ 17 std::filesystem::path对象.既然有std::filesystem::hash_value标准的一部分,为什么这个代码不能编译而不必我自己提供std::hash

当我使用gcc 8.1.1编译和链接时,g++ -std=c++17 -NO_HASH=1 hashtest.cpp -o hashtest -lstdc++fs我的哈希函数被包含在内并且一切运行完美.但是,如果我将其更改为-NO_HASH=0,我会得到一个很长的错误消息列表,其中一个关键是:

usr/include/c++/8/bits/hashtable.h:195:21: error: static assertion failed: hash function must be invocable with an argument of key type
       static_assert(__is_invocable<const _H1&, const _Key&>{},
Run Code Online (Sandbox Code Playgroud)

如果您想玩,这是一个现场Coliru版本.

真的没有定义std::hash<std::filesystem::path>吗? 我错过了什么?

对于那些对我为什么想要这样的东西感兴趣的人,就是这样:https://codereview.stackexchange.com/questions/124307/from-new-q-to-compiler-in-30-seconds

hashtest.cpp

#include <optional>
#include <unordered_set>
#include <filesystem>
#include <string>
#include <iostream>

namespace fs = std::filesystem;

#if NO_HASH
namespace std {
    template <>
    struct hash<fs::path> {
        std::size_t operator()(const fs::path &path) const {
            return hash_value(path);            }
    };
}
#endif
int main()
{
    using namespace std::literals;
    std::unordered_set< std::optional<fs::path> >  paths = {
            "/usr/bin"s, std::nullopt, "/usr//bin"s, "/var/log"s
    };

    for(const auto& p : paths)
        std::cout << p.value_or("(no path)") << ' ';
}
Run Code Online (Sandbox Code Playgroud)

Bar*_*rry 7

既然有std::filesystem::hash_value标准的一部分,为什么这个代码不能编译而不必我自己提供std::hash

是的,有一个,fs::hash_value()但没有专业化std::hash<fs::path>,这是你需要的.这就是为什么它不编译.至于为什么图书馆提供前者功能但不提供后者,我引用Billy O'Neal(MSVC标准库的实现者):

看起来像一个缺陷.

但是,将路径作为键放在哈希表中几乎肯定是不正确的; 您需要在大多数此类方案中测试路径等效性.也就是说,"/foo/bar/../baz"并且"/foo/baz"是相同的目标但不是相同的路径.类似地,"./bar"并且"./bar"可以是不同的路径,这取决于current_path第一上下文与第二上下文中的值.

如果你想要的是标准的独特路径,那么根本std::unordered_set<fs::path>就不会做你想要的.那么也许它编译失败并不是件坏事?关于文件系统,我不太了解这种或那种方式.


请注意,您自己提供std::hashfor 的特殊化fs::path是不允许的 - 您只能std为您控制的类型添加特化.将被称为"程序定义类型"的类型.fs::path不是你控制的类型,所以你不能专注std::hash于它.

  • 提示:您可以通过“fs::canonical(path)”将任何“fs::path”转换为规范路径。因此,如果您确保进入“std::unordered_set”的任何路径都是规范的,“std::unordered_set&lt;fs::path&gt;”就可以工作(除了缺少哈希)。 (3认同)