Heim  >  Artikel  >  Backend-Entwicklung  >  Wie kann „std::unordered_map“ funktionieren, ohne eine benutzerdefinierte Hash-Funktion zu definieren?

Wie kann „std::unordered_map“ funktionieren, ohne eine benutzerdefinierte Hash-Funktion zu definieren?

Barbara Streisand
Barbara StreisandOriginal
2024-11-06 19:41:02739Durchsuche

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

Generischer Hash für Tupel in unordered_map/unordered_set

F: Warum funktioniert std::unordered_map, string> funktionieren sofort?

Um in Standard-C Tupel als Schlüssel in assoziativen Containern wie unordered_map oder unordered_set zu verwenden, müssen Sie eine benutzerdefinierte Hash-Funktion definieren.

F: Kann dies für C 0x-Tupel automatisiert werden, ohne variadische Vorlagen zu verwenden?

Ja, unter Verwendung des folgenden Codes:

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;                                 
        }                                              
    };
}

F: Gibt es eine einfachere Lösung? ?

Standard-nicht-konforme Lösung (ADL-fähig):

#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;                                 
        }                                              
    };
}

Standard-konforme Lösung (kein ADL):

Um eine strikte Standardkonformität zu erreichen, müssen Sie den obigen Code in einen separaten Namespace (z. B. hash_tuple) verschieben und die Syntax ändern, um die benutzerdefinierte Hash-Funktion explizit anzugeben.

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);                                 
    }                                              
};
}

Ersetzen Sie hash_combine und HashValueImpl aus der nicht konformen Lösung mit ihren hash_tuple-Gegenstücken. Verwenden Sie abschließend die folgende Syntax:

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

Das obige ist der detaillierte Inhalt vonWie kann „std::unordered_map“ funktionieren, ohne eine benutzerdefinierte Hash-Funktion zu definieren?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn