Search code examples
c++hashenumsunordered-map

custom hash function for pair of enum values used as unordered_map key


I'm trying to use a std::pair of enum values as key for an unordered_map container, but I have difficulties in defining a custom hash function.

I tried the following:

// Enum and pair declaration
enum ShapeType{ PLANE, BOX, SPHERE };
typedef std::pair<ShapeType, ShapeType> ShapePair;

// unordered_map declaration
typedef void(*CollisionMethod)(const Shape*, const Shape*, CollisionData*);
typedef std::unordered_map<ShapePair, CollisionMethod, ShapePairHash> CollisionMethodsTable;

I don't understand how define correctly ShapePairHash functor. I tried the following:

struct ShapePairHash
{
    std::size_t operator()(const ShapePair &pair)
    {
        return std::hash<std::size_t>()(pair.first) ^ std::hash<std::size_t>()(pair.second);
    }
};

but I get error C3840 (expression having type 'type' would lose some const-volatile qualifiers in order to call 'function')on VS compiler.

Can anyone suggest me the right way to declare a custom hash function to be used with unordered_map?


Solution

  • You can define a last enum value, and then use it to generate the hash (actually a perfect hash). Note that this assume that the number of possible enum values is low enough so that (suppose that the number of enum values is N): N * N + N < MAX_UINT

    enum class ShapeType : unsigned int { PLANE = 0, BOX = 1, SPHERE = 2, LAST = 3 };
    
    struct ShapePairHash
    {
        std::size_t operator()(const ShapePair &pair) const
        {
          return static_cast<std::size_t>(pair.first)
               * static_cast<std::size_t>(ShapeType::LAST)
               + static_cast<std::size_t>(pair.second)
        }
    };
    

    Also, for your compilation problem you just need to declare the function const.