C ++ 0x fügt hinzu hash<...>(...)
.
Ich konnte jedoch keine hash_combine
Funktion finden , wie in Boost dargestellt . Was ist der sauberste Weg, um so etwas zu implementieren? Vielleicht mit C ++ 0x xor_combine
?
Nun, mach es einfach so, wie es die Boost-Jungs gemacht haben:
template <class T>
inline void hash_combine(std::size_t& seed, const T& v)
{
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
std::pair
(odertuple
sogar) zu haben. Es würde den Hash jedes Elements berechnen und sie dann kombinieren. (Und im Geiste der Standardbibliothek, in einer implementierungsdefinierten Weise.)Ich werde es hier teilen, da es für andere nützlich sein kann, die nach dieser Lösung suchen: Ausgehend von der Antwort von @KarlvonMoor ist hier eine variable Vorlagenversion, die in ihrer Verwendung kürzer ist, wenn Sie mehrere Werte miteinander kombinieren müssen:
Verwendung:
Dies wurde ursprünglich geschrieben, um ein variadisches Makro zu implementieren, um benutzerdefinierte Typen einfach hashbar zu machen (was meiner Meinung nach eine der Hauptverwendungen einer
hash_combine
Funktion ist):Verwendung:
quelle
Dies könnte auch durch Verwendung einer variablen Vorlage wie folgt gelöst werden:
Verwendung:
Man könnte sicherlich eine Vorlagenfunktion erstellen, aber dies könnte zu einem bösen Typabzug führen, z. B.
hash("Hallo World!")
wird ein Hash-Wert eher auf dem Zeiger als auf der Zeichenfolge berechnet. Dies ist wahrscheinlich der Grund, warum der Standard eine Struktur verwendet.quelle
Vor einigen Tagen habe ich eine leicht verbesserte Version dieser Antwort gefunden (C ++ 17-Unterstützung ist erforderlich):
Der obige Code ist in Bezug auf die Codegenerierung besser. Ich habe die qHash-Funktion von Qt in meinem Code verwendet, aber es ist auch möglich, andere Hascher zu verwenden.
quelle
(int[]){0, (hashCombine(seed, rest), 0)...};
und er funktioniert auch in C ++ 11.Ich mag den C ++ 17-Ansatz aus der Antwort von vt4a2h sehr , aber er hat ein Problem: Der
Rest
wird als Wert weitergegeben, während es wünschenswerter wäre, sie durch konstante Referenzen weiterzugeben (was ein Muss ist, wenn es sein soll verwendbar mit Nur-Verschieben-Typen).Hier ist die angepasste Version, die immer noch einen Fold-Ausdruck verwendet (weshalb C ++ 17 oder höher erforderlich ist) und verwendet
std::hash
(anstelle der Qt-Hash-Funktion):Der Vollständigkeit halber: Alle Typen , die mit dieser Version von benutzbar sein soll
hash_combine
muss eine haben Template - Spezialisierung fürhash
injiziert in denstd
Namespace.Beispiel:
Dieser Typ
B
im obigen Beispiel kann also auch in einem anderen Typ verwendet werdenA
, wie das folgende Verwendungsbeispiel zeigt:quelle
Hash
Vorlagenargumente der Standardcontainer zu verwenden, um Ihren benutzerdefinierten Hasher anzugeben, als ihn in denstd
Namespace einzufügen .Die Antwort von vt4a2h ist sicherlich nett, verwendet jedoch den C ++ 17-Fold-Ausdruck und nicht jeder kann problemlos zu einer neueren Toolchain wechseln. Die folgende Version verwendet den Expander-Trick, um einen Fold-Ausdruck zu emulieren, und funktioniert auch in C ++ 11 und C ++ 14 .
Zusätzlich habe ich die Funktion markiert
inline
und die perfekte Weiterleitung für die verschiedenen Vorlagenargumente verwendet.Live-Beispiel im Compiler Explorer
quelle