Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specializing std::hash for templated Key

I was trying to specialize hash for my own type, a templated key.

I was basing it off cppreference.

I get the compile error "The C++ Standard doesn't provide a hash for this type". I figure I just did it wrong. Could the compiler even support this kind of template?

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);
        }
    };
}
like image 654
Nyaarium Avatar asked Apr 27 '15 10:04

Nyaarium


Video Answer


1 Answers

There are a few issues with your code:

You are not allowed to place new definitions or declarations into the std namespace; only specializations (such as std::hash) are allowed. So your MyKey template should be moved out of the std namespace.

Your operator() signature is incorrect. MyKey doesn't name a type, you need to explicitly paramaterise it. Additionally, the operator should be marked const.

std::hash specializations should provide the member types argument_type and result_type.

If there are not existing specializations for the types passed in as SType etc., you need to provide them yourself.

You are not returning anything from your hash function, just computing the hashes of the other types and throwing their return values away.

An implementation which will compile for types which have their own std::hash specialization:

//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;
        }
    };
}
like image 84
TartanLlama Avatar answered Sep 19 '22 19:09

TartanLlama