Не удается использовать класс enum в качестве неупорядоченного ключа карты
у меня есть класс, содержащий класс enum.
class Shader {
public:
enum class Type {
Vertex = GL_VERTEX_SHADER,
Geometry = GL_GEOMETRY_SHADER,
Fragment = GL_FRAGMENT_SHADER
};
//...
затем, когда я реализую следующий код в другом классе...
std::unordered_map<Shader::Type, Shader> shaders;
...Я получаю ошибку компиляции.
...usr/lib/c++/v1/type_traits:770:38:
Implicit instantiation of undefined template 'std::__1::hash<Shader::Type>'
что вызывает ошибку здесь?
7 ответов:
Я использую объект функтора для вычисления хэша
enum class
:вы можете использовать его в качестве 3-го шаблона-параметрstruct EnumClassHash { template <typename T> std::size_t operator()(T t) const { return static_cast<std::size_t>(t); } };
std::unordered_map
:enum class MyEnum {}; std::unordered_map<MyEnum, int, EnumClassHash> myMap;
так что вам не нужно предоставлять специализацию
std::hash
, вычитание аргумента шаблона выполняет эту работу. Кроме того, вы можете использовать словоusing
и сделать свой собственныйunordered_map
чтобы использоватьstd::hash
илиEnumClassHash
в зависимости отKey
тип: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>>;
теперь вы можете использовать
MyUnorderedMap
Сenum class
или другой тип:MyUnorderedMap<int, int> myMap2; MyUnorderedMap<MyEnum, int> myMap3;
теоретически
HashType
можно использоватьstd::underlying_type
а тоEnumClassHash
не будет необходимости. Это может быть что-то вроде этого, но я еще не пробовал:template <typename Key> using HashType = typename std::conditional<std::is_enum<Key>::value, std::hash<std::underlying_type<Key>::type>, std::hash<Key>>::type;
при использовании
std::underlying_type
работы, смогли быть очень хорошим предложением для стандарта.
это считалось дефектом стандарта и было исправлено в C++14:http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2148
по состоянию на gcc 4.9.3, однако, это разрешение еще не реализовано в libstdc++:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970.
Это было исправлено в libc++ clang в 2013 году: http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20130902/087778.html
очень простым решением было бы предоставить объект хэш-функции следующим образом:
std::unordered_map<Shader::Type, Shader, std::hash<int> > shaders;
это все для ключа перечисления, нет необходимости предоставлять специализацию std:: hash.
как отметил KerrekSB, вам нужно предоставить специализацию
std::hash
Если вы хотите использоватьstd::unordered_map
, например:namespace std { template<> struct hash< ::Shader::Type > { typedef ::Shader::Type argument_type; typedef std::underlying_type< argument_type >::type underlying_type; typedef std::hash< underlying_type >::result_type result_type; result_type operator()( const argument_type& arg ) const { std::hash< underlying_type > hasher; return hasher( static_cast< underlying_type >( arg ) ); } }; }
при использовании
std::unordered_map
, вы знаете, вам нужна хэш-функция. Для встроенного илиSTL
типы, есть доступные по умолчанию, но не для определенных пользователем. Если вам просто нужна карта, почему бы вам не попробоватьstd::map
?