在自定义类中写哈希函数老是记不住,所以这次我特意举一个简单的例子:
写一个很简单的类,然后用哈希函数实现一个key的特化,以保证这个结构体可以被unordered_map或unordered_set用作key值。
代码如下:
#include <iostream>
#include <unordered_set>
using namespace std;
struct Score
{
int Chinese;
int math;
bool operator== (const Score& others) const
{
return tie(Chinese, math) == tie(others.Chinese, others.math);
}
};
namespace std
{
template<>
struct hash<Score>
{
size_t operator()(const Score& s) const
{
return hash<int>()(s.Chinese) ^ hash<int>()(s.math);
}
};
}
int main()
{
unordered_set<Score> set_Score;
set_Score.insert({0,0});
cout << "set_Score.size() is " << set_Score.size() << endl;
return 0;
}
程序输出是:
set_Score.size() is 1
上述代码是模板特化的示例,它为 std::hash 模板显式地提供了实现。接下来逐行解释下。
namespace std
{
这行代码将后面的代码放在 std 命名空间中。因为标准库中的模板都是写在 std 命名空间中的,如 std::hash 模板。如果你想对标准库中的模板进行特化,那么你必须在同一个命名空间中定义你的模板特化。否则,编译器将无法找到你的模板特化,并会使用标准库中默认的模板实现。
template<>
struct hash<Score>
这2行代码显式地对 std::hash 模板进行特化。这意味着,当编译器遇到 std::hash 时,它将使用你提供的显式模板特化实现,而不会使用默认的模板实现。
size_t operator()(const Score& s) const
这行代码定义了 std::hash 模板特化的哈希函数。哈希函数接受一个 Score 对象作为参数,并返回一个 size_t 类型的值。
return hash<int>()(s.Chinese) ^ hash<int>()(s.math);
这行代码是哈希函数的具体实现。它将 Score 对象的 Chinese 和 math 字段组合起来作为哈希值。
哈希函数的实现细节如下:
hash()(s.Chinese): 使用默认的整数哈希函数对 s.Chinese 字段进行哈希计算。
hash()(s.math): 使用默认的整数哈希函数对 s.math 字段进行哈希计算。
^: 使用异或运算符将两个哈希值组合起来。
组合后的哈希值是一个 size_t 类型的整数,它可以被 unordered_map 和 unordered_set 用作键值。
因此,这段代码的作用是为 Score 对象提供了一个哈希函数,使 Score 对象可以被 unordered_map 和 unordered_set 用作键值。