Специализация std::hash для шаблонного ключа

Я пытался специализировать хеш для своего собственного типа, шаблонного ключа.

Я основывал это на cppreference.

Я получаю ошибку компиляции "Стандарт C++ не предоставляет хэш для этого типа". Я полагаю, я просто сделал это неправильно. Может ли компилятор даже поддерживать такой шаблон?

namespace std {
    template<typename SType, typename AType, typename PType>
    struct MyKey {
        const SType from;
        const AType consume;
        const PType pop;
    };

    template<typename SType, typename AType, typename PType>
    struct hash<MyKey<SType, AType, PType>> {
        size_t operator ()(MyKey const &key) {
            std::hash<SType>()(key.from);
            std::hash<AType>()(key.consume);
            std::hash<PType>()(key.pop);
        }
    };
}

1 ответ

Решение

Есть несколько проблем с вашим кодом:

Вам не разрешено размещать новые определения или объявления в std Пространство имен; только специализации (такие как std::hash) разрешены. Так что ваши MyKey шаблон должен быть удален из std Пространство имен.

Ваш operator() подпись неверна. MyKey не называет тип, вам нужно явно его преобразовать. Кроме того, оператор должен быть отмечен const,

std::hash специализации должны предоставлять типы членов argument_type а также result_type,

Если не существует специализаций для типов, переданных как SType и т.д., вы должны предоставить их сами.

Вы ничего не возвращаете из своей хеш-функции, просто вычисляете хеши других типов и выбрасываете их возвращаемые значения.

Реализация, которая будет компилироваться для типов, которые имеют свои собственные std::hash специализация:

//moved out of std
template<typename SType, typename AType, typename PType>
struct MyKey {
    const SType from;
    const AType consume;
    const PType pop;
};

namespace std {
    template<typename SType, typename AType, typename PType>
    struct hash<MyKey<SType, AType, PType>>{
        //member types
        using argument_type = MyKey<SType,AType,PType>;
        //arguments specified         ^     ^     ^
        using result_type = std::size_t;

        result_type operator ()(argument_type const& key) const {
        //marked const                                      ^
            //these will fail if SType and friends don't have a std::hash specialization
            result_type s_hash = std::hash<SType>()(key.from);
            result_type a_hash = std::hash<AType>()(key.consume);
            result_type p_hash = std::hash<PType>()(key.pop);

            //in your actual code, you'll want to compute the return type from the above
            return p_hash;
        }
    };
}
Другие вопросы по тегам