我正在尝试用C++实现一个类,我希望每个类都有自己的hashcode实现(基本上将它用作unordered_map
&中的键unordered_set
)
例如:
class CustomClass{
int a;
vector<int> b;
string c;
bool operator ==(const CustomClass& o) const{
return ((a == o.a) && (b == o.b) && (c == o.c));
}
/*
Is it possible to define the hashcode function here instead of defining it outside the class.
size_t operator()() const {
// Some custom logic for calculating hash of CustomClass using
// the hash Values of its individual fields
std::size_t h = 0;
for(int& t : b){
h = (h ^ std::hash<int>()(t)) << 1;
}
return (h^(std::hash<int>()(a) << 1))^( std::hash<string>()(c) << 1);
}
*/
};
Run Code Online (Sandbox Code Playgroud)
现在,假设我想在unordered_map中使用它
int main(){
unoredered_map<CustomClass, int> m;
}
Run Code Online (Sandbox Code Playgroud)
我有两个选择,
i)使用Template specialization在std命名空间中注入hashcode
namespace std {
template <> struct hash<CustomClass> {
size_t operator()(const CustomClass& o) const {
// Some custom logic for calculating hash of CustomClass using
// the hash Values of its individual fields
size_t h = 0;
for(int& t : o.b){
h = (h ^ std::hash<int>()(t)) << 1;
}
return (h^(std::hash<int>()(o.a) << 1))^( std::hash<string>()(o.c) << 1);
}
};
}
Run Code Online (Sandbox Code Playgroud)
要么
ii.)在实例化时每次创建unordered_map
(或unordered_set
)时指定此功能,即
struct HashSpecialer {
std::size_t operator()(const CustomClass& o) const {
std::size_t h = 0;
for(int& t : o.b){
h = (h ^ std::hash<int>()(t)) << 1;
}
return (h^(std::hash<int>()(o.a) << 1))^( std::hash<string>()(o.c) << 1);
}
};
Run Code Online (Sandbox Code Playgroud)
在实例化时unordered_map
,我提供了这个结构.
int main(){
unoredered_map<CustomClass, int, HashSpecialer> m;
}
Run Code Online (Sandbox Code Playgroud)
我找到了两种方法,混淆使用(i)污染std命名空间和(ii)通过记住每次实例化时提供HashSpecializer使其变得困难 unordered_map
是否有可能在类定义本身中提供哈希码函数,正如我在上面的代码片段中的注释部分中所描述的那样
public class CustomClass {
int a;
List<Integer> b;
String c;
// I Let my IDE generate these methods :D
@Override public boolean equals(Object o)
{
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
CustomClass that = (CustomClass) o;
if (a != that.a)
return false;
if (b != null ? !b.equals(that.b) : that.b != null)
return false;
return c != null ? c.equals(that.c) : that.c == null;
}
// This one too :D
@Override public int hashCode()
{
int result = a;
result = 31 * result + (b != null ? b.hashCode() : 0);
result = 31 * result + (c != null ? c.hashCode() : 0);
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
我正在寻找这样的东西,因为这证明非常方便.
我认为你的问题的解决方案是调整你对美学上令人愉悦的C++程序的理解.
专门化std::hash
不会污染std命名空间,相反,您应该考虑这std::hash
是用于控制如何unordered_map
使用类的自定义点 .
这样的特化是类的接口的一部分(并且可以是类的朋友),其方式与二元运算符完全相同,例如operator +()
应该是非成员函数,并且仍然是接口的一部分.