如何直接使用密钥作为std::unordereded_map的散列

How to directly use key as hash for std::unordered_map?

本文关键字:unordereded map std 何直接 密钥      更新时间:2023-10-16

我的std::unordered_map中的键是boost::uuids::uuids,因此128位散列被认为是唯一的。然而,编译器不知道这一点,因此会这样说。

error C2338: The C++ Standard doesn't provide a hash for this type.

我如何使地图使用关键字作为散列?顺便说一句,在我的系统上,std::size_t被定义为unsigned int __w64,我认为它只指64位。

您总是需要提供一个函数对象,将键映射到哈希值,即使该映射是标识。您可以为std::hash<boost::uuids::uuid>定义一个专门化,并让std::unordered_map<K, V>自动选择这个,也可以使用函数对象类型的附加模板参数来参数化无序映射。除了散列之外,还需要一个相等操作,但默认情况下,使用operator==()可能是可以的

也就是说,除非您的系统具有内置的128位整数类型,否则哈希值不会接受128位整数。散列值必须是std::size_t才能用于标准无序容器。std::hash<T>专业化的完整需求列表在20.8.12[unord.hash]:中列出

  1. std::hash<X>需要是默认可构造的、可复制可构造的和可复制可赋值的
  2. std::hash<X>需要可更换
  3. 它需要为密钥类型提供两个嵌套类型argument_type,为散列值的类型提供result_type,后者与std::size_t相同
  4. 对于函数,关系k1 == k2=>h(k1) == h(k2)需要为真,其中h是散列函数对象

因此,您需要定义以下内容:

namespace std {
    template <>
    struct hash<boost::uuids::uuid>
    {
        typedef boost::uuids::uuid argument_type;
        typedef std::size_t        result_type;
        std::size_t operator()(boost::uuid::uuid key) const {
            return transform_to_size_t(key);
        }
    };
}

其中transform_to_size_t()是您需要提供的实际转换。};

您需要为类型boost::uuids::uuid提供一个散列函数。由于它是唯一的,您可以使用stl身份。

这是unordered_map的声明。

template < class Key,                                    // unordered_map::key_type
           class T,                                      // unordered_map::mapped_type
           class Hash = hash<Key>,                       // unordered_map::hasher
           class Pred = equal_to<Key>,                   // unordered_map::key_equal
           class Alloc = allocator< pair<const Key,T> >  // unordered_map::allocator_type
           > class unordered_map;

我认为最简单的方法是为这些类型实现std::hash的专门化,它返回相同的输入:

namespace std
{
    template<>
    struct hash<Foo>
    {
        Foo operator(const Foo& foo)
        {
            return foo;
        }
    };
}

假设类型,在示例中为Foo,可以隐式转换为std::size_t

在您的情况下,类型是128位的GUID,而std::size_t使用32或64位。您可以将128位的GUID拆分为64/32位的部分,然后组合这些值。

我找不到将UUID用作std::unordered_map的密钥的方法,因为UUID是128位长,而映射的哈希是只能容纳64位的std::size_t

相反,我只删除了64位ID的实际128位UUID,这些ID可以存储在uint64_t类型中,并且由标准库的容器本地支持。