Использование ha sh непосредственно в методах из unordered_map вместо пользовательского объекта, создающего хеш - PullRequest
0 голосов
/ 10 февраля 2020

Итак, я создал класс, который я использую как ха sh в unordered_map

class MyClass
{
  hash_type mHash = 0;
  hash_type hash() { return mHash; }

  bool operator!= (const MyClass& rhs) const;
  bool operator== (const MyClass& rhs) const;
}
namespace std
{
    template <>
    struct hash<MyClass>
    {
        hash_type operator()(const MyClass& k) const noexcept
        {
            return k.hash();
        }
    };
}

Он работает, как и ожидалось, но я хотел бы добавить некоторые функциональные возможности. Я хотел бы иметь возможность использовать сам ha sh при использовании функций unordered_map, таких как find и erase. Теперь я должен сделать это:

void _erase_key(const MyClass& key) { umap.erase(key); }

Но я хотел бы также сделать это:

void _erase_key(const hash_type key) { umap.erase(key); }

Можно ли как-то напрямую использовать ha sh вместо объекта, производящего ха sh при использовании таких методов, как find и erase?

1 Ответ

2 голосов
/ 11 февраля 2020

Если я вас правильно понимаю, вы хотите иметь std::unordered_map<MyClass, Value> такой, что вы также можете запросить с помощью hash_type, и у вас будет hash_type h == MyClass m, если std::hash<MyClass>{}(m) == h. Это правильно?

Это невозможно в C ++ 17. С C ++ 20 будет добавлена ​​функциональность прозрачных хешей . Вы можете прочитать об этом очень кратко здесь . При этом ваша карта должна удовлетворять определенным свойствам

  • Ваш тип равенства Eq должен предоставлять тип элемента Eq::is_transparent, т.е. вы должны указать в нем using is_transparent = some_type;. (Точный тип без последствий.)
  • Объект типа Eq должен обеспечивать перегрузку для сравнения всех возможных комбинаций типов, которые вы хотите использовать. Т.е. обеспечивают перегрузки для (MyClass, MyClass) и (MyClass, hash_type).
  • Ваш тип ha sh Hash должен предоставить тип элемента Hash::transparent_key_equal, поэтому снова вставьте в него using transparent_key_equal = some_type;.
  • Объект типа Hash должен вызываться для каждого типа, который вы хотите использовать. Т.е. у вас должна быть перегрузка operator() для MyClass и hash_type.

Для Eq вы можете использовать std::equal_to<> (обратите внимание на пустой ромб!), Если вы предоставляете публично доступно operator== для соответствующих типов. Это НЕ по умолчанию для unordered_map.

Насколько мне известно, нет никакого аналагона для std::hash, поэтому вы должны добавить собственный тип для этого и предоставить его на карту.

Pre-C ++ 20 единственное, что вы можете сделать, если хотите сохранить тип ключа, - это записать преобразование из hash_type в MyClass.

Но я чувствую фундаментальную проблему в этом, а именно, что вы видите два объекта MyClass как идентичные, если они имеют одинаковое значение ha sh. Если это непреднамеренно, вы должны это исправить. Если это преднамеренно, убедитесь, что operator==(MyClass, MyClass) также сравнивает только хэши.

В последующем случае есть простое решение вашей проблемы. Измените вашу карту на std::unordered_map<hash_type, Value> и ha sh каждый MyClass, который вы используете для запроса карты. Если вам нужен обратный поиск, чтобы получить MyClass из га sh, либо напишите функцию преобразования из hash_type в MyClass, если это возможно, в противном случае добавьте еще один std::unordered_map<hash_type, MyClass>, где вы храните каждый объект типа MyClass вы когда-либо использовали.

...