Maison >développement back-end >C++ >Comment faire fonctionner `std::unordered_map` sans définir de fonction de hachage personnalisée ?

Comment faire fonctionner `std::unordered_map` sans définir de fonction de hachage personnalisée ?

Barbara Streisand
Barbara Streisandoriginal
2024-11-06 19:41:02825parcourir

How to Make `std::unordered_map` Work Without Defining a Custom Hash Function?

Hash générique pour les tuples dans unordered_map/unordered_set

Q : Pourquoi std::unordered_map, chaîne> fonctionne-t-il immédiatement ?

En C standard, pour utiliser des tuples comme clés dans des conteneurs associatifs comme unordered_map ou unordered_set, vous devez définir une fonction de hachage personnalisée.

Q : Cela peut-il être automatisé pour les tuples C 0x sans utiliser de modèles variadiques ?

Oui, en utilisant le code suivant :

namespace std{
    namespace
    {
        template <class T>
        inline void hash_combine(std::size_t&amp; seed, T const&amp; v)
        {
            seed ^= std::hash<T>()(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
        }

        template <class Tuple, size_t Index = std::tuple_size<Tuple>::value - 1>
        struct HashValueImpl
        {
          static void apply(size_t&amp; seed, Tuple const&amp; tuple)
          {
            HashValueImpl<Tuple, Index-1>::apply(seed, tuple);
            hash_combine(seed, std::get<Index>(tuple));
          }
        };

        template <class Tuple>
        struct HashValueImpl<Tuple,0>
        {
          static void apply(size_t&amp; seed, Tuple const&amp; tuple)
          {
            hash_combine(seed, std::get<0>(tuple));
          }
        };
    }

    template <typename ... TT>
    struct hash<std::tuple<TT...>> 
    {
        size_t
        operator()(std::tuple<TT...> const&amp; tt) const
        {                                              
            size_t seed = 0;                             
            HashValueImpl<std::tuple<TT...> >::apply(seed, tt);    
            return seed;                                 
        }                                              
    };
}

Q : Existe-t-il une solution plus simple ?

Solution standard non conforme (ADL activée) :

#include 
namespace std{
    namespace
    {
        template <class T>
        inline void hash_combine(std::size_t&amp; seed, T const&amp; v)
        {
            seed ^= std::hash<T>()(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
        }

        template <class Tuple, size_t Index = std::tuple_size<Tuple>::value - 1>
        struct HashValueImpl
        {
          static void apply(size_t&amp; seed, Tuple const&amp; tuple)
          {
            HashValueImpl<Tuple, Index-1>::apply(seed, tuple);
            hash_combine(seed, std::get<Index>(tuple));
          }
        };

        template <class Tuple>
        struct HashValueImpl<Tuple,0>
        {
          static void apply(size_t&amp; seed, Tuple const&amp; tuple)
          {
            hash_combine(seed, std::get<0>(tuple));
          }
        };
    }

    template <typename ... TT>
    struct hash<std::tuple<TT...>> 
    {
        size_t
        operator()(std::tuple<TT...> const&amp; tt) const
        {                                              
            size_t seed = 0;                             
            HashValueImpl<std::tuple<TT...> >::apply(seed, tt);    
            return seed;                                 
        }                                              
    };
}

Solution conforme aux standards (Non ADL) :

Pour obtenir une conformité stricte aux normes, vous devez déplacer le code ci-dessus dans un espace de noms distinct (par exemple, hash_tuple) et modifier la syntaxe pour spécifier explicitement la fonction de hachage personnalisée.

namespace hash_tuple{

// Forward non-tuple types to std::hash
template <typename TT>
struct hash
{
    size_t
    operator()(TT const&amp; tt) const
    {                                              
        return std::hash<TT>()(tt);                                 
    }                                              
};
}

Remplacez hash_combine et HashValueImpl de la solution non conforme par leurs homologues hash_tuple. Enfin, utilisez la syntaxe suivante :

unordered_set<tuple<double, int>, hash_tuple::hash<tuple<double, int>>> test2;

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn