Heim > Artikel > Backend-Entwicklung > Wie kann „std::unordered_map“ funktionieren, ohne eine benutzerdefinierte Hash-Funktion zu definieren?
Generischer Hash für Tupel in unordered_map/unordered_set
F: Warum funktioniert std::unordered_map
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& seed, T const& 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& seed, Tuple const& 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& seed, Tuple const& tuple) { hash_combine(seed, std::get<0>(tuple)); } }; } template <typename ... TT> struct hash<std::tuple<TT...>> { size_t operator()(std::tuple<TT...> const& 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):
#includenamespace std{ namespace { template <class T> inline void hash_combine(std::size_t& seed, T const& 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& seed, Tuple const& 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& seed, Tuple const& tuple) { hash_combine(seed, std::get<0>(tuple)); } }; } template <typename ... TT> struct hash<std::tuple<TT...>> { size_t operator()(std::tuple<TT...> const& 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& 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!