Program Tip

열거 형 클래스를 무순 맵 키로 사용할 수 없습니다.

programtip 2020. 10. 28. 20:32
반응형

열거 형 클래스를 무순 맵 키로 사용할 수 없습니다.


열거 형 클래스를 포함하는 클래스가 있습니다.

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

여기서 오류의 원인은 무엇입니까?


나는 functor 객체를 사용하여 다음의 해시를 계산합니다 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>>;

이제 MyUnorderedMapwith 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

이는 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


매우 간단한 해결책은 다음과 같은 해시 함수 객체를 제공하는 것입니다.

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습니까?


MyEnumClass를 정의하는 헤더에 다음을 추가하십시오.

namespace std {
  template <> struct hash<MyEnumClass> {
    size_t operator() (const MyEnumClass &t) const { return size_t(t); }
  };
}

시험

std::unordered_map<Shader::Type, Shader, std::hash<std::underlying_type<Shader::Type>::type>> shaders;

참고 URL : https://stackoverflow.com/questions/18837857/cant-use-enum-class-as-unordered-map-key

반응형