Reputation: 63
So i have created a class that i use as a hash in an 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();
}
};
}
It works as expected but i would like to add some functionality. I would like to be able to use the hash itself when using unordered_map functions like find and erase. Now i have to do this:
void _erase_key(const MyClass& key) { umap.erase(key); }
But i would like to be able to do this as well:
void _erase_key(const hash_type key) { umap.erase(key); }
Is it possible to somehow use the hash directly instead of the object producing the hash when using methods like find and erase?
Upvotes: 0
Views: 132
Reputation: 5085
If I understand you right, you want to have an std::unordered_map<MyClass, Value>
such that you can also query with hash_type
and you have hash_type h == MyClass m
if std::hash<MyClass>{}(m) == h
. Is this correct?
This is not possible in C++17. With C++20, there will be added the functionality of transparent hashes. You can read about that very briefly here. With this, your map has to fulfill certain properties
Eq
must provide a member type Eq::is_transparent
, i.e. you have to put a using is_transparent = some_type;
in it. (The exact type is without consequence.) Eq
has to provide an overload to compare all possible combinations of types you want to use. I.e. provide overloads for (MyClass, MyClass)
and (MyClass, hash_type)
.Hash
has to provide a member type Hash::transparent_key_equal
, so again, put using transparent_key_equal = some_type;
in it.Hash
must be callable with every type you want to use. I.e. you have to have an operator()
overload for both MyClass
and hash_type
.For Eq
you can use std::equal_to<>
(note the empty diamond!) if you provide publically accessible operator==
for the appropriate types. This is NOT the default for unordered_map
.
There is to the best of my knowledge no analagon for std::hash
, so you have to add an own type for that and provide it to the map.
Pre-C++20 the only thing you can do if you want to keep your key type is to write a conversion from hash_type
to MyClass
.
But I sense a fundamental problem in this, namely that you see two objects of MyClass
as identical if they have the same hash. If this is unintentional, you should really fix this. If it is intentional, make sure, that operator==(MyClass, MyClass)
also only compares hashes.
In the later case, there is an easy fix for your problem. Change your map to std::unordered_map<hash_type, Value>
and hash each MyClass
you use to query the map. If you need a reverse lookup to get MyClass
from a hash, either write a conversion function from hash_type
to MyClass
if this is possible, otherwise add another std::unordered_map<hash_type, MyClass>
, where you store every object of type MyClass
you ever use.
Upvotes: 3