Maison > Article > développement back-end > Comment faire fonctionner `std::unordered_map` sans définir de fonction de hachage personnalisée ?
Hash générique pour les tuples dans unordered_map/unordered_set
Q : Pourquoi std::unordered_map
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& 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; } }; }
Q : Existe-t-il une solution plus simple ?
Solution standard non conforme (ADL activée) :
#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; } }; }
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& 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!