c++ - validar - No se puede usar la clase enum como clave desordenada_mapa
validar enum java (7)
Agregue esto al encabezado que define MyEnumClass:
namespace std {
template <> struct hash<MyEnumClass> {
size_t operator() (const MyEnumClass &t) const { return size_t(t); }
};
}
Tengo una clase que contiene una clase enum.
class Shader {
public:
enum class Type {
Vertex = GL_VERTEX_SHADER,
Geometry = GL_GEOMETRY_SHADER,
Fragment = GL_FRAGMENT_SHADER
};
//...
Luego, cuando implemente el siguiente código en otra clase ...
std::unordered_map<Shader::Type, Shader> shaders;
... Recibo un error de compilación.
...usr/lib/c++/v1/type_traits:770:38:
Implicit instantiation of undefined template ''std::__1::hash<Shader::Type>''
¿Qué está causando el error aquí?
Como señaló KerrekSB, debe proporcionar una especialización de std::hash
si desea usar std::unordered_map
, algo así como:
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 ) );
}
};
}
Cuando usas std::unordered_map
, sabes que necesitas una función hash. Para los tipos incorporados o STL
, hay valores predeterminados disponibles, pero no para los definidos por el usuario. Si solo necesitas un mapa, ¿por qué no pruebas std::map
?
Esto se consideró un defecto en el estándar, y se corrigió en C ++ 14: http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2148
A partir de gcc 4.9.3, sin embargo, esta resolución aún no está implementada en libstdc ++: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970 .
Se corrigió en la biblioteca de clang ++ en 2013: http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20130902/087778.html
Tratar
std::unordered_map<Shader::Type, Shader, std::hash<std::underlying_type<Shader::Type>::type>> shaders;
Una solución muy simple sería proporcionar un objeto de función hash como este:
std::unordered_map<Shader::Type, Shader, std::hash<int> > shaders;
Eso es todo por una clave enum, no es necesario proporcionar una especialización de std :: hash.
Utilizo un objeto de functor para calcular el hash de la enum class
:
struct EnumClassHash
{
template <typename T>
std::size_t operator()(T t) const
{
return static_cast<std::size_t>(t);
}
};
Ahora puede usarlo como el tercer parámetro de plantilla de std::unordered_map
:
enum class MyEnum {};
std::unordered_map<MyEnum, int, EnumClassHash> myMap;
Por lo tanto, no necesita proporcionar una especialización de std::hash
, la deducción del argumento de la plantilla hace el trabajo. Además, puede usar la palabra using
y crear su propio EnumClassHash
unordered_map
que use std::hash
o EnumClassHash
dependiendo del tipo de 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>>;
Ahora puedes usar MyUnorderedMap
con la enum class
u otro tipo:
MyUnorderedMap<int, int> myMap2;
MyUnorderedMap<MyEnum, int> myMap3;
Teóricamente, HashType
podría usar std::underlying_type
y luego EnumClassHash
no será necesario. Eso podría ser algo como esto, pero aún no lo he intentado :
template <typename Key>
using HashType = typename std::conditional<std::is_enum<Key>::value, std::hash<std::underlying_type<Key>::type>, std::hash<Key>>::type;
Si se usa std::underlying_type
, podría ser una muy buena propuesta para el estándar.