Reputation: 4572
How do I create a hash function for key as pair of string and enum to be used in unordered_map?
I have the following pair which is the key to an unordered map how do I create a hash so it can be used in unordered_map?
enum Color {
Red,
Green
};
typedef std::pair <std::string, Color>
I tried the following but got compilation error
struct EnumClassHash
{
template <typename T>
std::size_t operator()(T t) const
{
return static_cast<std::size_t>(t);
}
};
size_t hash( const PairType & pair ) {
return std::hash<std::string>()(pair.first) ^
std::hash<EnumClassHash>()(pair.second);
}
typedef std::unordered_map<PairType, std::string>,
std::function<decltype(hash)>> ColorMapType;
error: invalid use of incomplete type 'struct std::hash<EnumClassHash>'
std::hash<EnumClassHash>()(pairType.second);
The following isnt working either
size_t hash( const PairType & pairType ) {
return std::hash<std::string>()(pairType.first) ^
std::hash<Color>()(pairType.second);
}
typedef std::unordered_map<PairType, std::string, \
std::function<decltype(hash)>> ColorMapType;
ColorMapType colorMap(100, hash);
error: invalid use of incomplete type 'struct std::hash<Color>'
std::hash<Color>()(pair.second
);
PS Pardon my formatting. I lost my gmail password and can only post from mobile app which is a tiny screen.
Upvotes: 1
Views: 2793
Reputation:
struct EnumClassHash
, it is its own thing, not a specialization of std::hash
.std::hash<EnumClassHash>()(pair.second)
, the template specialization std::hash<EnumClassHash>
simply doesn't exist.You can either:
struct EnumClassHash
, and use EnumClassHash
, orstd::hash
into std::hash<Color>
, and use std::hash<Color>
, orbut never mix and match part of each method, which does not make any kind of sense.
Also, to use std::pair<std::string, Color>
as the key type of std::unordered_map
, neither std::hash<Color>
nor EnumClassHash
matters. What matters is std::hash<std::pair<std::string, Color>>
or your own class that hashes std::pair<std::string, Color>
.
Here is a recipe you can follow.
To use std::pair<std::string, Color>
as key type, you need to specialize std::hash<std::pair<std::string, Color>>
yourself.
template <>
struct std::hash<std::pair<std::string, Color>>
{
std::size_t operator()(const std::pair<std::string, Color>& p) const {
return std::hash<std::string>()(p.first) ^ std::hash<Color>()(p.second);
}
};
But before that, you need to specialize std::hash<Color>
first since std::hash<std::pair<std::string, Color>>
uses it.
template <>
struct std::hash<Color>
{
std::size_t operator()(Color c) const {
return static_cast<size_t>(c);
}
};
Then, you can use something like std::unordered_map<std::pair<std::string, Color>, std::string>
. No EnumClassHash
involved.
If you love EnumClassHash
very much, here is another recipe.
You can keep EnumClassHash
as you like.
struct EnumClassHash
{
template <typename T>
std::size_t operator()(T t) const
{
return static_cast<std::size_t>(t);
}
};
This time, std::hash<Color>
does not exist. Don't use it. (Not to mention std::hash<EnumClassHash>
which does not make sense.)
So, the class that hash the key type should use EnumClassHash
. (Once again, not std::hash<EnumClassHash>
!)
struct PairHash {
std::size_t operator()(const std::pair<std::string, Color>& p) const {
return std::hash<std::string>()(p.first) ^ EnumClassHash()(p.second);
}
};
Now, you can use std::unordered_map<std::pair<std::string, Color>, std::string, PairHash>
.
Upvotes: 3