不能使用枚举类作为 unordered_map 键

新手上路,请多包涵

我有一个包含枚举类的类。

 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>'

是什么导致了这里的错误?

原文由 Appleshell 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 2.1k
2 个回答

我使用仿函数对象来计算 enum class 的哈希值:

 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 的特化,模板参数推导就可以了。 Furthermore, you can use the word using and make your own unordered_map that use std::hash or EnumClassHash depending on the 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>>;

现在您可以将 MyUnorderedMapenum 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 有效,可能是该标准的一个很好的建议。

原文由 Daniel 发布,翻译遵循 CC BY-SA 3.0 许可协议

当我想将 unordered_map 从枚举类型转换为字符串时,我遇到了类似的问题。

您很可能不需要 unordered_map。因为您使用枚举类作为键,所以我假设您不需要像插入或删除这样的操作:简单的查找就足够了。

话虽如此,为什么不直接使用函数呢?

 // assume shader_vertex, shader_geometry, shader_fragment are initialized
Shader* toShader(Shader::Type value){
  switch(value){
    case Shader::Type::Vertex:
      return &shader_vertex;
    case Shader::Type::Geometry:
      return &shader_geometry;
    case Shader::Type::Fragment:
      return &shader_fragment;
    default:
      //some error handling..
      return nullptr;
}

与其他解决方案不同,这种方法与编译器无关。

学分转到此 项目链接

原文由 Fengggli 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题