如何直接使用key作为std :: unordered_map的哈希?

时间:2013-08-31 13:16:17

标签: c++ hash std uuid unordered-map

std::unordered_map中的密钥为boost::uuids::uuid,因此128位哈希值被视为唯一。但是,编译器无法知道,因此说明了这一点。

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

如何让地图将密钥用作哈希值?顺便说一句,std::size_t在我的系统中被定义为unsigned int __w64,我认为它只涉及64位。

4 个答案:

答案 0 :(得分:2)

即使此映射是标识,您始终需要提供将键映射到散列值的函数对象。您可以为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 =&gt; h(k1) == h(k2)必须为h是散列函数对象。
  5. 因此,您需要按照以下方式定义:

    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()是您需要提供的实际转化。         };

答案 1 :(得分:1)

您需要为类型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;

答案 2 :(得分:0)

我认为最简单的方法是为这些类型实现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位。您可以将64位GUID拆分为64/32位的部分,并组合这些值。

答案 3 :(得分:0)

我发现没有办法使用UUID作为std::unordered_map的密钥,因为UUID是128位长,而地图的哈希是std::size_t,只能容纳64位。

相反,我删除了真正的128位UUID,只有64位ID,可以存储在uint64_t类型中,并且标准库的容器本身支持。