Reputation: 25928
I have a funny error occuring where I have a custom class I am using as keys in a std::unordered_map
. I have implemented a hash function for this custom class.
If I create an std::unordered_map
like so everything runs fine:
std::unordered_map <Component, int> myMap;
But if I create a std::unordered_map
where the keys are references it complains there is no implemented hash function for this type:
std::unordered_map <Component&, int> myMap;
Error 3 error C2338: The C++ Standard doesn't provide a hash for this type.
Any idea how I can get this to work?
class Component
{
public:
GUID id;
Component()
{
generateGUID(&id);
}
bool operator== (const Component& other) const
{
return compareGUID(id, other.id);
}
};
namespace std
{
template<>
struct hash<Component>
{
std::size_t operator()(const Component& cmp) const
{
using std::size_t;
using std::hash;
return hash<GUID>()(cmp.id); // GUID hash has also been implemented
}
};
}
std::unordered_map<Component, int> cMap1; // compiles ok
std::unordered_map<Component&, int> cMap2; // causes compiler error
Upvotes: 3
Views: 1447
Reputation: 133577
The problem is not how to correctly override hash for Component&
. The problem is that STL containers are meant to store objects and references are not objects. Mind that the term object includes primitives and pointers, since they require storage, while a reference does not.
To overcome your problem you should look into std::reference_wrapper
, which is able to wrap a reference inside an object, then the code would become something like:
#include <iostream>
#include <unordered_map>
#include <functional>
using namespace std;
struct Component
{
size_t id;
};
namespace std
{
template<>
struct hash<reference_wrapper<Component>>
{
size_t operator()(const reference_wrapper<Component>& cmp) const
{
return cmp.get().id;
}
};
}
unordered_map<reference_wrapper<Component>, int> mapping;
If you don't want to use reference_wrapper then you should use pointers (Component*
) as keys.
Upvotes: 3