【问题标题】:hash function in c++ for a custom type [duplicate]c ++中用于自定义类型的哈希函数[重复]
【发布时间】:2020-07-08 02:30:24
【问题描述】:

我尝试编写一些自定义函数,而不是允许在 unordered_set 模板中使用我的自定义结构。

我有结构:

struct test_record {
    int value;
    std::string name;
};

还有哈希运算符:

namespace std {

    template<> struct hash<test_record> {

        using argument_type = test_record;
        using result_type = size_t;

        size_t operator()(const test_record& r) const {

            const std::hash<std::string> str_hash_fn;
            const std::hash<int> int_hash_fn;

            const size_t result = str_hash_fn(r.name) ^ int_hash_fn(r.value);

            return result;
        }
    };
};

像这样使用它:

int main()
{

    std::unordered_set <test_record> myrecordsset;

    myrecordsset.insert({ 1, "one" }); // error!

}

但是编译器会抛出错误信息:

1>E:\开发\视觉 Studio\VC\Tools\MSVC\14.25.28610\include\xstddef(91,22):错误 C2676: 二进制 '==': 'const _Ty' 未定义此运算符或转换 到预定义运算符 1> 和 1>
可接受的类型 [ 1> _Ty=test_record 1> ] 1>E:\开发\视觉 Studio\VC\Tools\MSVC\14.25.28610\include\xstddef(90):消息:同时 编译类模板成员函数'bool std::equal_to::operator ()(const _Ty &,const _Ty &) const' 1> 与 1> [ 1> _Ty=test_record 1>
] 1>E:\开发\视觉 Studio\VC\Tools\MSVC\14.25.28610\include\xhash(164):消息:见 引用函数模板实例化 'bool std::equal_to::operator ()(const _Ty &,const _Ty &) const' 正在编译 1> 与 1> [ 1>
_Ty=test_record 1> ] 1>E:\Development\Visual Studio\VC\Tools\MSVC\14.25.28610\include\xmemory(1318):消息:见 引用类模板实例化 'std::equal_to' 正在编译 1>E:\Development\Visual Studio\VC\Tools\MSVC\14.25.28610\include\xmemory(1318):消息:见 引用变量模板'const bool is_empty_v >' 正在编译 1>E:\开发\视觉 Studio\VC\Tools\MSVC\14.25.28610\include\unordered_set(30):消息: 请参阅对类模板实例化的参考 'std::_Uhash_compare<_kty>' 正在编译 1>
与 1> [ 1> _Kty=test_record, 1>
_Hasher=std::hash, 1> _Keyeq=std::equal_to 1> ] 1>E:\Development\Visual Studio\VC\Tools\MSVC\14.25.28610\include\xhash(342):消息:见 引用类模板实例化 'std::_Uset_traits<_kty>,_Alloc,false>' 正在编译 1> 与 1> [ 1>
_Kty=test_record, 1> _Hasher=std::hash, 1> _Keyeq=std::equal_to, 1> _Alloc=std::allocator 1> ] 1>E:\Development\Visual Studio\VC\Tools\MSVC\14.25 .28610\include\unordered_set(65): 消息: 请参阅对类模板实例化的参考 'std::_Hash,_Alloc,false>>' 正在编译 1> 与 1> [ 1>
_Kty=test_record, 1> _Hasher=std::hash, 1> _Keyeq=std::equal_to, 1> _Alloc=std::allocator 1> ] 1>E:\Development_Projects\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.cpp(20) : 消息:参见对类模板实例化的参考 'std::unordered_set,std::equal_to,std::allocator>' 正在编译

这有什么问题吗?为什么编译器需要在 unordered_set 中使用 equal_to 运算符?

【问题讨论】:

  • 您还需要一个operator== 来检查是否相等。自己散列是不够的。由于散列冲突是一回事,标准实现在散列之上使用相等比较。
  • 如果您没有相等运算符,您将如何检查是否确实找到了正确的记录,而不仅仅是具有相同哈希的记录?

标签: c++ hash structure


【解决方案1】:

集合的意义在于它不包含两个相同的对象。仅通过查看哈希无法确定身份,因此您需要具体的相等比较。 C++ 要求您明确地为您的类定义相等性,以防您需要任何特殊行为。

添加这个应该可以解决问题:

namespace std {
    template<> struct equal_to<test_record> {
        using argument_type = test_record;
        using result_type = bool;
        constexpr bool operator()(const test_record &lhs, const test_record &rhs) const {
            return (lhs.name == rhs.name) && (lhs.value == rhs.value);
        }
    };
};

【讨论】:

  • operator== 可以很好地实现equal_to 的专业化时似乎有点迂回。如果没有可用的专业化,这就是 equal_to 的回退。
  • 当然。只是认为它非常适合上述哈希运算符,并且如果需要不同的operator== 行为,则可以单独关注。事后看来,我同意在这种情况下不太可能,但在一般情况下,例如,人们可能希望通过引用将事物存储在一个集合中,但通过它们的值来区分它们。
  • 当然,如果你足够努力的话,它可能会有用例。如果您这样做,您可能会破坏例如&lt;algorithm&gt; 标头。期待operator== 在实际上你的专业化开始时使用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-15
  • 2020-08-23
相关资源
最近更新 更多