J’essaie de créer une unordered_map pour mapper des paires avec des entiers.
#include using namespace std; using Vote = pair; using Unordered_map = unordered_map;
J’ai une classe où j’ai déclaré un Uneredered_map en tant que membre privé.
Cependant, je reçois cette erreur lorsque j’essaie de comstackr:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/type_traits:948:38: Implicit instantiation of undefined template 'std::__1::hash<std::__1::pair<std::__1::basic_string, std::__1::basic_ssortingng > >'
Je n’obtiens pas cette erreur si j’utilise une carte régulière telle que map<pair, int>
au lieu d’une map<pair, int>
non ordonnée.
N’est-il pas possible d’utiliser une pair
comme clé dans des cartes non ordonnées?
Vous devez fournir une fonction de hachage adaptée à votre type de clé. Un exemple simple:
#include #include #include #include // Only for pairs of std::hash-able types for simplicity. // You can of course template this struct to allow other hash functions struct pair_hash { template std::size_t operator () (const std::pair &p) const { auto h1 = std::hash{}(p.first); auto h2 = std::hash{}(p.second); // Mainly for demonstration purposes, ie works but is overly simple // In the real world, use sth. like boost.hash_combine return h1 ^ h2; } }; using Vote = std::pair; using Unordered_map = std::unordered_map; int main() { Unordered_map um; }
Cela fonctionnera, mais n’aura pas les meilleures propriétés de hachage † . Vous voudrez peut-être jeter un coup d’œil à quelque chose comme boost.hash_combine
pour obtenir des résultats de meilleure qualité lors de la combinaison des hachages.
Pour une utilisation réelle: Boost fournit également la fonction hash_value
qui fournit déjà une fonction de hachage pour std::pair
, ainsi que std::tuple
et la plupart des conteneurs standard.
† Plus précisément, cela produira trop de collisions. Par exemple, chaque paire symésortingque hachera à 0 et les paires qui ne diffèrent que par permutation auront le même hachage. C’est probablement bien pour votre exercice de programmation, mais cela pourrait sérieusement nuire aux performances du code réel.
Pour résoudre ce problème, ma méthode préférée consiste à définir une fonction key
qui transforme votre paire en un entier unique (ou tout type de données à caractère extensible). Cette clé n’est pas la clé de hachage. C’est l’ID unique de la paire de données qui sera ensuite hachée de manière optimale par le unordered_map
. Par exemple, vous vouliez définir une unordered_map
du type
unordered_map,double> Map;
Et vous voulez utiliser Map[make_pair(i,j)]=value
ou Map.find(make_pair(i,j))
pour fonctionner sur la carte. Ensuite, vous devrez dire au système comment hacher une paire d’entiers make_pair(i,j)
. Au lieu de cela, nous pouvons définir
inline size_t key(int i,int j) {return (size_t) i << 32 | (unsigned int) j;}
puis changez le type de la carte en
unordered_map Map;
Nous pouvons maintenant utiliser Map[key(i,j)]=value
ou Map.find(key(i,j))
pour opérer sur la carte. Chaque make_pair
maintenant la fonction de key
inline.
Cette méthode garantit que la clé sera hachée de manière optimale, car à présent, la partie de hachage est effectuée par le système, qui choisira toujours la taille de la table de hachage interne comme étant optimale pour garantir la même probabilité pour chaque compartiment. Mais vous devez vous assurer à 100% que la key
est unique pour chaque paire, c'est-à-dire que deux paires distinctes ne peuvent pas avoir la même clé ou qu'il peut y avoir des bogues très difficiles à trouver.
Comme votre erreur de compilation l’indique, il n’y a pas d’instanciation valide de std::hash
dans votre espace de noms std.
Selon mon compilateur:
Erreur C2338 La norme C ++ ne fournit pas de hachage pour ce type. c: \ fichiers de programme (x86) \ microsoft visual studio 14.0 \ vc \ include \ xstddef 381
Vous pouvez fournir votre propre spécialisation pour std::hash
comme suit:
#include #include #include using namespace std; using Vote = pair; using Unordered_map = unordered_map; namespace std { template<> struct hash { size_t operator()(Vote const& v) const { // ... hash function here ... } }; } int main() { Unordered_map m; }
Pour la clé de paire, nous pouvons utiliser la fonction de hachage de paire renforcée:
#include #include #include using namespace std; int main() { unordered_map, int, boost::hash>> m; m[make_pair("123", "456")] = 1; cout << m[make_pair("123", "456")] << endl; return 0; }
De même, nous pouvons utiliser le hachage de boost pour les vecteurs,
#include #include #include #include using namespace std; int main() { unordered_map, int, boost::hash>> m; vector a({"123", "456"}); m[a] = 1; cout << m[a] << endl; return 0; }