6

I want to use a unordered_map<std::pair<enum_class,other_enum_class>,std::uint8_t> for managing some pixelmap formats.

Here the minimal code :

#include <unordered_map>
#include <utility>
#include <cstdint> 
#include <iostream>
#include <functional>

enum class PNM : std::uint8_t { PBM, PGM, PPM };
enum class Format : bool      { BIN, ASCII };

struct pair_hash {
public:
    template <typename T, typename U>
    std::size_t operator()(const std::pair<T, U> &x) const { 
        return std::hash<T>()(x.first) ^ std::hash<U>()(x.second); 
    }
};

int main(){

    std::unordered_map<std::pair<PNM, Format>, std::uint8_t, pair_hash> k_magic_number ({
        { { PNM::PBM, Format::BIN   }, 1 }, { { PNM::PGM, Format::BIN   }, 2 }, { { PNM::PPM, Format::BIN   }, 3 },
        { { PNM::PBM, Format::ASCII }, 4 }, { { PNM::PGM, Format::ASCII }, 5 }, { { PNM::PPM, Format::ASCII }, 6 }
    });

    std::cout << k_magic_number[std::make_pair<PNM, Format>(PNM::PBM, Format::BIN)];
}

With GCC I have an error when I try to instantiate the class :

main.cpp:14:24: error: invalid use of incomplete type 'struct std::hash'
return std::hash()(x.first) ^ std::hash()(x.second);
In file included from
/usr/local/include/c++/5.2.0/bits/basic_string.h:5469:0,
from /usr/local/include/c++/5.2.0/string:52,
[...]

With Clang I also have an error :

error: implicit instantiation of undefined template 'std::hash' return std::hash()(x.first) ^ std::hash()(x.second); /usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/bits/hashtable_policy.h:1257:16: note: in instantiation of function template specialization 'pair_hash::operator()' requested here [...]

With VS2013 I have no error and the code compile and executes.

What is missing in my code ?

1
  • Depending on your need, you can also consider using std::map, which does not have the hashing requirement. Commented Mar 2, 2016 at 22:35

1 Answer 1

8

g++-5 gives following errors:

invalid use of incomplete type struct std::hash<PNM>

invalid use of incomplete type struct std::hash<Format>

So, you should just specialize std::hash for PNM and Format.

namespace std {
template<>
struct hash<PNM>
{
   typedef PNR argument_type;
   typedef size_t result_type;

   result_type operator () (const argument_type& x) const
   {
      using type = typename std::underlying_type<argument_type>::type;
      return std::hash<type>()(static_cast<type>(x));
   }
};

template<>
struct hash<Format>
{
   typedef Format argument_type;
   typedef size_t result_type;       

   result_type operator () (const argument_type& x) const
   {
      using type = typename std::underlying_type<argument_type>::type;
      return std::hash<type>()(static_cast<type>(x));
   }
};

}

Or you can write template struct, that will works only for enums with use of SFINAE (not sure, that it's not UB by standard, since it's not specialization actually).

namespace std
{

template<typename E>
struct hash
{
   typedef E argument_type;
   typedef size_t result_type;
   using sfinae = typename std::enable_if<std::is_enum<E>::value>::type;
     
   result_type operator() (const E& e) const
   {
      using base_t = typename std::underlying_type<E>::type;
      return std::hash<base_t>()(static_cast<base_t>(e));
   }
};

}
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you I'll try that aren't these supposed to already have a specialization since there are basically bools and integers ?
@coincoin they are enum classes , that is different type from int.
Thanks @ForEveR this compiles and executes. But how come my std::cout is not printed ?
@coincoin: it is, but ASCII code 1 isn't a "printable" (visible) character - it's a control code that terminals and that web site don't necessarily show in any useful way. Try cout << (int)... to cast it to int such that the ASCII value is shown.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.