87

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?

4

7 回答 7

126

我使用函子对象来计算的散列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,模板参数推导就可以完成这项工作。此外,您可以使用该词并根据类型使用或using制作自己的词:unordered_mapstd::hashEnumClassHashKey

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

现在您可以使用MyUnorderedMapwithenum 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作品,可能是该标准的一个很好的建议。

于 2014-07-20T04:50:52.840 回答
60

这被认为是标准中的一个缺陷,并在 C++14 中得到了修复:http ://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2148

这在自 6.1 起随 gcc 一起发布的 libstdc++ 版本中得到了修复:https ://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970 。

它于 2013 年在 clang 的 libc++ 中修复:http: //lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20130902/087778.html

于 2015-04-14T03:14:44.817 回答
25

一个非常简单的解决方案是提供一个像这样的哈希函数对象:

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

这就是枚举键的全部内容,无需提供 std::hash 的专门化。

于 2014-03-12T19:10:03.863 回答
6

将此添加到定义 MyEnumClass 的标题中:

namespace std {
  template <> struct hash<MyEnumClass> {
    size_t operator() (const MyEnumClass &t) const { return size_t(t); }
  };
}
于 2016-02-09T23:54:44.600 回答
5

正如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 ) );
        }
    };
}
于 2013-09-16T22:01:12.107 回答
4

当你使用 时std::unordered_map,你知道你需要一个散列函数。对于内置或STL类型,有可用的默认值,但不适用于用户定义的。如果你只需要一张地图,为什么不试试std::map呢?

于 2013-09-16T21:51:46.363 回答
-1

尝试

std::unordered_map<Shader::Type, Shader, std::hash<std::underlying_type<Shader::Type>::type>> shaders;
于 2015-12-15T22:15:39.557 回答