[英]Is there a default hash function for an unordered_set of a custom class?
我第一次使用std::unordered_set
並且對哈希函數有疑問。 據我所知,如果你沒有指定一個哈希函數,它將默認為std::hash<Key>
。
我的一個mySet
有一個mySet
成員:
typedef std::unordered_set<MyClass> USetType;
USetType mySet;
當我嘗試構建時,我收到以下錯誤:
錯誤C2440:'type cast':無法從'const MyClass'轉換為'size_t'
如果要將unordered_set
與自定義類一起使用,是否需要定義轉換函數(to size_t
)? 有沒有辦法避免編寫自己的哈希函數並只使用默認值?
如果您沒有將自己的散列函數指定為模板參數,則默認為std::hash<MyClass>
,除非您定義它,否則它不存在。
最好在命名空間std
定義你自己的std::hash
專業化:
namespace std {
template <>
struct hash<MyClass>
{
typedef MyClass argument_type;
typedef std::size_t result_type;
result_type operator()(const MyClass & t) const
{
/* ..calculate hash value for t */
}
};
}
並確保在聲明哈希之前包含此代碼。 這樣,您可以將哈希聲明為std::unordered_set<MyClass>
,而無需進一步的模板參數。
你沒有指定MyClass
里面的內容,但典型的情況是你的用戶定義類型只包含幾個簡單類型的成員,其中存在一個默認的哈希函數。 在這種情況下,您可能希望將各個類型的哈希值組合為整個組合的哈希值。 為此,Boost庫提供了一個名為hash_combine
的函數。 當然,不能保證它在您的特定情況下能夠很好地工作(它取決於數據值的分布和碰撞的可能性),但它提供了一個好的且易於使用的起點。
下面是一個如何使用它的示例,假設MyClass
包含兩個字符串成員:
#include <unordered_set>
#include <boost/functional/hash.hpp>
struct MyClass
{
std::string _s1;
std::string _s2;
};
namespace std {
template <>
struct hash<MyClass>
{
typedef MyClass argument_type;
typedef std::size_t result_type;
result_type operator()(const MyClass & t) const
{
std::size_t val { 0 };
boost::hash_combine(val,t._s1);
boost::hash_combine(val,t._s2);
return val;
}
};
}
int main()
{
std::unordered_set<MyClass> s;
/* ... */
return 0;
}
我想在擴大答案通過jogojapan給出。 正如CashCow對該答案的評論中所提到的,您還必須為MyClass
重載相等比較運算符 ( operator==
)或定義單獨的比較函數並將其提供給unordered_set
。 否則,您將收到另一條錯誤消息。 例如,VS 2013拋出:
錯誤C2678:二進制'==':找不到哪個運算符帶有'const MyClass'類型的左操作數(或者沒有可接受的轉換)
此外,您可以使用lambda表達式而不是定義哈希和比較函數。 如果你不想使用Boost ,那么你也可以手工編寫一個哈希函數 。 我明白,你想使用一些默認函數,但編譯器不知道如何為自定義類計算有意義的哈希。 但是,您可以對類的成員使用std::hash
。 如果你把所有東西放在一起,那么你的代碼可以寫成如下:
class MyClass {
public:
int i;
double d;
std::string s;
};
int main()
{
auto hash = [](const MyClass& mc){
return (std::hash<int>()(mc.i) * 31 + std::hash<double>()(mc.d)) * 31 + std::hash<std::string>()(mc.s);
};
auto equal = [](const MyClass& mc1, const MyClass& mc2){
return mc1.i == mc2.i && mc1.d == mc2.d && mc1.s == mc2.s;
};
std::unordered_set<MyClass, decltype(hash), decltype(equal)> mySet(8, hash, equal);
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.