Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't use enum class as unordered_map key

I have a class containing an enum class.

class Shader { public:     enum class Type {         Vertex   = GL_VERTEX_SHADER,         Geometry = GL_GEOMETRY_SHADER,         Fragment = GL_FRAGMENT_SHADER     };     //... 

Then, when I implement the following code in another class...

std::unordered_map<Shader::Type, Shader> shaders; 

...I get a compile error.

...usr/lib/c++/v1/type_traits:770:38:  Implicit instantiation of undefined template 'std::__1::hash<Shader::Type>' 

What is causing the error here?

like image 334
Appleshell Avatar asked Sep 16 '13 21:09

Appleshell


2 Answers

I use a functor object to calculate hash of enum class:

struct EnumClassHash {     template <typename T>     std::size_t operator()(T t) const     {         return static_cast<std::size_t>(t);     } }; 

Now you can use it as 3rd template-parameter of std::unordered_map:

enum class MyEnum {};  std::unordered_map<MyEnum, int, EnumClassHash> myMap; 

So you don't need to provide a specialization of std::hash, the template argument deduction does the job. Furthermore, you can use the word using and make your own unordered_map that use std::hash or EnumClassHash depending on the Key type:

template <typename Key> using HashType = typename std::conditional<std::is_enum<Key>::value, EnumClassHash, std::hash<Key>>::type;  template <typename Key, typename T> using MyUnorderedMap = std::unordered_map<Key, T, HashType<Key>>; 

Now you can use MyUnorderedMap with enum class or another type:

MyUnorderedMap<int, int> myMap2; MyUnorderedMap<MyEnum, int> myMap3; 

Theoretically, HashType could use std::underlying_type and then the EnumClassHash will not be necessary. That could be something like this, but I haven't tried yet:

template <typename Key> using HashType = typename std::conditional<std::is_enum<Key>::value, std::hash<std::underlying_type<Key>::type>, std::hash<Key>>::type; 

If using std::underlying_type works, could be a very good proposal for the standard.

like image 72
Daniel Avatar answered Sep 20 '22 03:09

Daniel


This was considered a defect in the standard, and was fixed in C++14: http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2148

This is fixed in the version of libstdc++ shipping with gcc as of 6.1: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970.

It was fixed in clang's libc++ in 2013: http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20130902/087778.html

like image 29
David Stone Avatar answered Sep 20 '22 03:09

David Stone