1. ホーム
  2. c++

[解決済み] enum クラスを unordered_map のキーとして使用することはできません。

2023-05-05 12:48:26

質問

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

ここでエラーの原因となっているのは何でしょうか?

どのように解決するのですか?

のハッシュを計算するためにファンクタオブジェクトを使用しています。 enum class :

struct EnumClassHash
{
    template <typename T>
    std::size_t operator()(T t) const
    {
        return static_cast<std::size_t>(t);
    }
};

の3番目のテンプレート・パラメータとして使用することができます。 std::unordered_map :

enum class MyEnum {};

std::unordered_map<MyEnum, int, EnumClassHash> myMap;

の特殊化を提供する必要はないわけです。 std::hash の特殊化を提供する必要はなく、テンプレートの引数deductionが仕事をします。さらに 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 が機能するならば、標準のための非常に良い提案になるかもしれません。