代码之家  ›  专栏  ›  技术社区  ›  Edward

“STD::文件系统::路径”没有标准散列吗?

  •  4
  • Edward  · 技术社区  · 6 年前

    我有一个简单的程序,用于存储一组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&>{},
    

    这是一个 live Coliru version 如果你想玩的话。

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

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

    哈希测试.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)") << ' ';
    }
    
    2 回复  |  直到 6 年前
        1
  •  7
  •   rioki    6 年前

    std::filesystem::hash_value std::hash

    对,有一个 fs::hash_value() std::hash<fs::path> ,这是你需要的。这就是它不编译的原因。至于图书馆为什么提供前一种功能而不是后一种功能,我将引用 Billy O'Neal

    看起来像个缺陷。

    "/foo/bar/../baz" "/foo/baz" "./bar" current_path

    std::unordered_set<fs::path>


    请注意,您自己提供了 对于 fs::path std fs::路径 为了它。

        2
  •  1
  •   Yakk - Adam Nevraumont    6 年前
    namespace hashing {
      namespace adl {
        template<class T, class...Ts>
        auto hash_value( T const& t, Ts&&... )
        -> std::result_of_t< std::hash<T>&&(T const&) >
        {
          return std::hash<T>{}(t);
        }
        template<class T>
        auto hasher_private( T const& t )
        -> decltype( hash_value( t ) )
        { return hash_value(t); }
      }
    
      struct smart_hasher {
        template<class T>
        auto operator()( T const& t ) const
        ->decltype( adl::hasher_private( t ) )
        {    return adl::hasher_private( t ); }
      };      
    };
    

    hashing::smart_hasher 是将要查找的哈希对象 hash_value(T const&) T 如果失败,将使用 std::hash<T>

    std hash_value 功能过载输入 hashing::adl .对于其他类型,请在其关联的命名空间中创建它。例如,如果要支持哈希 tuple S:

    namespace hashing::adl {
      template<class...Ts>
      std::size_t hash_value( std::tuple<Ts...> const& tup ) {
        // get hash values and combine them here
        // use `smart_hasher{}( elem ) to hash each element for
        // recursive smart hashing
      }
    }
    

    现在有人用 smart_hasher 自动为提供该定制的任何内容选取散列值。