web-dev-qa-db-fra.com

erreur pour la fonction de hachage d'une paire d'ints

J'ai la classe suivante avec un unordered_map membre, et une fonction de hachage définie pour pair<int,int>

class abc
{public :
    unordered_map < pair<int,int> , int > rules ;
    unsigned nodes;
    unsigned packet ;     
};

namespace std {
template <>
    class hash < std::pair< int,int> >{
    public :
        size_t operator()(const pair< int, int> &x ) const
        {
            size_t h =   std::hash<int>()(x.first) ^ std::hash<int>()(x.second);
            return  h ;
        }
    };
}

Mais je reçois les erreurs suivantes:

error: invalid use of incomplete type ‘struct std::hash<std::pair<int, int> >

error: declaration of ‘struct std::hash<std::pair<int, int> >

error: type ‘std::__detail::_Hashtable_ebo_helper<1, std::hash<std::pair<int, int> >, true>’ is not a direct base of ‘std::__detail::_Hash_code_base<std::pair<int, int>, std::pair<const std::pair<int, int>, int>, std::__detail::_Select1st, std::hash<std::pair<int, int> >, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, true>’
32
Shambo

Malheureusement, ce programme a un comportement indéfini. C++ 11 §17.6.4.2.1:

Un programme peut ajouter une spécialisation de modèle pour tout modèle de bibliothèque standard à l'espace de noms std uniquement si la déclaration dépend d'un type défini par l'utilisateur et que la spécialisation répond aux exigences de bibliothèque standard pour le modèle d'origine et n'est pas explicitement interdite.

hash<pair<int,int>> dépend uniquement des types de bibliothèques primitifs et standard. Pour résoudre ce problème, définissez votre classe de hachage en dehors de l'espace de noms std et utilisez ce hachage de manière explicite dans votre déclaration de carte:

struct pairhash {
public:
  template <typename T, typename U>
  std::size_t operator()(const std::pair<T, U> &x) const
  {
    return std::hash<T>()(x.first) ^ std::hash<U>()(x.second);
  }
};

class abc {
  std::unordered_map<std::pair<int,int>, int, pairhash> rules;
};

EDIT: J'ai utilisé xor pour combiner les hachages des membres de la paire ici parce que je suis paresseux, mais pour une utilisation sérieuse xor est une fonction de combinaison de hachage assez merdique .

45
Casey

Je préfère m'appuyer sur l'implémentation standard de std::hash<uintmax_t> pour mélanger les hachages des composants d'un std::pair:

#include <functional>
#include <utility>

struct hash_pair final {
    template<class TFirst, class TSecond>
    size_t operator()(const std::pair<TFirst, TSecond>& p) const noexcept {
        uintmax_t hash = std::hash<TFirst>{}(p.first);
        hash <<= sizeof(uintmax_t) * 4;
        hash ^= std::hash<TSecond>{}(p.second);
        return std::hash<uintmax_t>{}(hash);
    }
};
0