Что не так с operator()
внутри Entity
(хэшером)?
Копирование-вставка в отдельный struct
работает:
#include <bitset>
#include <unordered_map>
using namespace std;
struct Entity {
string name;
size_t operator()(const Entity& k) const noexcept
{ return std::hash<string>{}(k.name); }
bool operator== (const Entity& e) const noexcept
{ return e.name == name; }
};
struct KeyHasher {
size_t operator()(const Entity& k) const noexcept
{ return std::hash<string>{}(k.name); }
};
int main(){
// unordered_map<const Entity, bitset<24>, KeyHasher> m1; // OK
unordered_map<const Entity, bitset<24>> m2; // unordered_map() ill-formed ?
return 0;
}
Ошибка :
<source>: In function 'int main()':
<source>:25:43: error: use of deleted function 'std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map()
[with _Key = const Entity; _Tp = std::bitset<24>; _Hash = std::hash<const Entity>; _Pred = std::equal_to<const Entity>; _Alloc = std::allocator<std::pair<const Entity, std::bitset<24> > >]'
25 | unordered_map<const Entity, bitset<24>> m2;
| ^~
In file included from /opt/compiler-explorer/gcc-cxx-modules-trunk-20220427/include/c++/11.0.0/unordered_map:47,
from <source>:3:
/opt/compiler-explorer/gcc-cxx-modules-trunk-20220427/include/c++/11.0.0/bits/unordered_map.h:141:7: note: 'std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map() [with _Key = const Entity; _Tp = std::bitset<24>; _Hash = std::hash<const Entity>; _Pred = std::equal_to<const Entity>; _Alloc = std::allocator<std::pair<const Entity, std::bitset<24> > >]'
is implicitly deleted because the default definition would be ill-formed:
141 | unordered_map() = default;
код в вашей ссылке выглядит нормально, код компилируется. В чем проблема?
карта никогда не использует value_type::operator()
. непонятно, почему вы так думаете
Нет смысла иметь константные ключи, поскольку существующие ключи остаются неизменными внутри карты.
@ 463035818 : вопрос обновлен. оператор вызывает std::hash()
, чтобы предоставить уникальный хэш Entity
.
@ExpertNoob1 Карта не использует перегрузку operator()
для типа ключа для вычисления хеша.
@molbdnilo: значит, хэш-функция не может быть частью Entity
, перегружая оператор, она должна быть собственной struct
?
Довольно много, но это может быть любая вызываемая вещь или тип. (Ну, вы могли бы сказать unordered_map<Entity, bitset<24>, Entity>
, но это привело бы к созданию Entity
по умолчанию только для вычисления хэша других экземпляров Entity
. Он не будет вызывать e(e)
, когда вы хотите добавить e
.)
Если вы не укажете хэш-функцию для своей карты, по умолчанию она будет равна std::hash<Key>
с вашим типом ключа.
Поэтому вам нужно будет определить эту специализацию std::hash
template<>
struct std::hash<const Entity>
{
std::size_t operator()(const Entity const& k) const noexcept
{
return std::hash<string>{}(k.name);
}
}
Спасибо. Мое замешательство возникло из-за использования техники перегрузки операторов с помощью unordered_set
, которая действительно работает !! См. добавление Record
в godbolt.org/z/zaPecMz13. Не улавливайте разницы между map
и set
в этом отношении. Оба нуждаются в хешировании ключей!
@ExpertNoob1 operator()
должен находиться в отдельной структуре, которую затем можно указать как хэш. Не в классе, который вы там храните. Что касается unordered_set
, вы указали bitset<24>
в качестве хэша (который недействителен, но, похоже, ломается только при попытке туда что-то вставить).
@ExperNoob1 вы могли бы использовать unordered_map<const Entity, bitset<24>,Entity>
, чтобы использовать Entity
как тип ключа и как хэш одновременно, хотя это необычно и сбивает с толку. Я не знаю ни одного контейнера, использующего свои типы элементов operator()
.
@ExpertNoob1 Попробуйте добавить что-нибудь в свой unordered_set
и увидите, что это не удается. Затем сделайте это unordered_set<Record>
и посмотрите, как он продолжает терпеть неудачу.
@HolyBlackCat первая версия ссылки OP использовала саму запись в качестве хэша, что могло бы работать, но этого не следует делать. Для текущей ссылки она не прерывается, потому что, пока вы не попытаетесь использовать функции, вызывающие хэшер, она на самом деле не попытается вызвать ее (и сломать). std::map
нужно синтезировать hasher(pair<key, value>)
из hasher(key)
, поэтому он всегда использует его.
@HolyBlackCat: я вдвойне сбит с толку!! Действительно, я использовал Record
как собственный хэшер !! Никогда не было проблем с этой программой, но все же... Я согласен с @463035818: это смешно! О боже.
@ExpertNoob1 "Никогда не было проблем с этой программой" Какая программа? Использование типа в качестве собственного хэша обычно расточительно, так как каждый набор/карта будет хранить его дополнительный экземпляр только для вычисления хэшей. Не говоря уже о том, что пользователи хэша могут быть сбиты с толку ()
вычислением хэша.
Я сделал небольшой гаджет (многопоточное удаление огромного списка файлов/папок из входного файла), который использует unordered_set
из Record
s для удаления дубликатов из списка папок, которые в результате становятся пустыми (тоже должны быть удалены), и он хешировал Record
против самого себя. Собрал, работал годами без проблем. Но да: расточительно и запутанно (например, вы можете подумать, что это сработает с map
s, и попытаетесь увековечить бессмыслицу!).
для чего вы ожидаете, что
Entiry::operator()
будет использоваться?