Я пытаюсь объявить unordered_multiset, который будет содержать объекты пользовательского класса, но я не могу найти никаких примеров для этого. Следуя документации, кажется, что мне нужно объявить operator==
в классе вместе с хеш-функцией (operator() const
), которая, согласно документации:
Key
.std::size_t
, представляющее хэш-значение параметра.std::hash<Key>()(k1) == std::hash<Key>()(k2)
.std::hash<Key>()(k1) == std::hash<Key>()(k2)
должен быть очень маленьким, приближаясь к 1.0/std::numeric_limits<std::size_t>::max()
.Код выглядит очень упрощенно так:
Класс МойКласс:
// comparator
bool MyClass::operator ==(const MyClass b) const {
return (string == b.getString()); // compares two strings
}
// hash operation
size_t MyClass::operator()() const {
return hash<string>()(string); // bases the hash on the string
}
основной.cpp:
unordered_multiset<MyClass> s1;
// Also tried: unordered_multiset<MyClass, std::hash<MyClass>, std::equal_to<MyClass>> s1;
Однако при установке unordered_multiset
компилятор (GCC) будет жаловаться на хэш-функции (Tupla — это имя MyClass, а там более 1000 строк, я включил несколько из них):
error: use of deleted function ‘std::unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset() [with _Value = Tupla; _Hash = std::hash<Tupla>; _Pred = std::equal_to<Tupla>; _Alloc = std::allocator<Tupla>]’
78 | unordered_multiset<Tupla> s1;
| ^~
/usr/include/c++/10/bits/unordered_set.h:949:7: note: ‘std::unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset() [with _Value = Tupla; _Hash = std::hash<Tupla>; _Pred = std::equal_to<Tupla>; _Alloc = std::allocator<Tupla>]’ is implicitly deleted because the default definition would be ill-formed:
949 | unordered_multiset() = default;
/usr/include/c++/10/bits/unordered_set.h:949:7: error: use of deleted function ‘std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_Hashtable() [with _Key = Tupla; _Value = Tupla; _Alloc = std::allocator<Tupla>; _ExtractKey = std::__detail::_Identity; _Equal = std::equal_to<Tupla>; _H1 = std::hash<Tupla>; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<true, true, false>]’
In file included from /usr/include/c++/10/unordered_set:46,
/usr/include/c++/10/bits/hashtable.h:451:7: note: ‘std::_Hashtable<_Key, _Value, _Alloc, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, _Traits>::_Hashtable() [with _Key = Tupla; _Value = Tupla; _Alloc = std::allocator<Tupla>; _ExtractKey = std::__detail::_Identity; _Equal = std::equal_to<Tupla>; _H1 = std::hash<Tupla>; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; _Traits = std::__detail::_Hashtable_traits<true, true, false>]’ is implicitly deleted because the default definition would be ill-formed:
451 | _Hashtable() = default;
Распределитель также упоминается как необходимое условие для unordered_multiset, но я не понимаю его и не уверен, следует ли его включать (или как).
Что я пропустил?
откуда вы взяли, что MyClass::operator()()
используется для хеша? (вы правильно цитируете, что это std::hash<Key>()(k1)
) Или здесь опечатка и MyClass::operator()()
на самом деле std::hash<MyClass>::operator()()
?
вы можете заменить строку своей структурой, я думаю:
#include <bits/stdc++.h>
using namespace std;
// Custom Hash Functor that will compute the hash on the
// passed string objects length
struct StringHashBySize {
public:
size_t operator()(const std::string & str) const {
int size = str.length();
return std::hash<int>()(size);
}
};
// Custom comparator that compares the string objects by length
struct StringEqualBySize {
public:
bool operator()(const std::string & str1, const std::string & str2) const {
if (str1.length() == str2.length())
return true;
else
return false;
}
};
int main() {
// Declaring unordered_multiset with Custom Hash Function and comparator
unordered_multiset<std::string, StringHashBySize, StringEqualBySize> multiset;
return 0;
}
Это сработало (используя класс, конечно), большое спасибо! Я отмечу ваш ответ как принятый, поскольку он был «первым», хотя ответ @fabian также действителен (я думаю, это протокол в таких ситуациях?)
рада, если помогла ^^
Простейшим способом сделать это, вероятно, будет вспомогательный класс для реализации хэша:
struct MyClassHash
{
const std::hash<std::string> m_stringHash {};
size_t operator()(const MyClass& value) const
{
return m_stringHash(value.getString());
};
};
и используйте это для хеширования:
std::unordered_multiset<MyClass, MyClassHash> s1;
Кстати, я рекомендую передавать параметр как ссылку на operator==
, а не копировать:
bool operator==(const MyClass& other) const;
Большое спасибо! Я пометил ответ Деви Хос как принятый, так как он был ранее, но ваш тоже вполне действителен и полезен (Кроме того, обратите внимание на передачу ссылки, я пропустил это...)
пожалуйста, включите минимальный воспроизводимый пример вашего кода в вопрос