Comment se spécialisent std::hash<Key>::operator() pour le type défini par l'utilisateur non ordonnée dans les conteneurs?
À l'appui de l'utilisateur a défini les principaux types de std::unordered_set<Key>
et std::unordered_map<Key, Value>
on doit fournir operator==(Key, Key)
et un hachage foncteur:
struct X { int id; /* ... */ };
bool operator==(X a, X b) { return a.id == b.id; }
struct MyHash {
size_t operator()(const X& x) const { return std::hash<int>()(x.id); }
};
std::unordered_set<X, MyHash> s;
Il serait plus commode d'écrire juste std::unordered_set<X>
avec un de hachage par défaut pour le type X
,
comme pour les types à venir avec le compilateur et de la bibliothèque.
Après consultation de
- C++ Standard Projet De N3242 §20.8.12 [unord.hash] et §17.6.3.4 [hachage.exigences],
- Coup de pouce.Non ordonnée
- g++
include\c++\4.7.0\bits\functional_hash.h
- VC10
include\xfunctional
- divers une question relative à las dans le Débordement de la Pile
il semble possible de se spécialiser std::hash<X>::operator()
:
namespace std { //argh!
template <>
inline size_t
hash<X>::operator()(const X& x) const { return hash<int>()(x.id); } //works for MS VC10, but not for g++
//or
//hash<X>::operator()(X x) const { return hash<int>()(x.id); } //works for g++ 4.7, but not for VC10
}
Compte tenu de prise en charge du compilateur de C++11 est encore expérimental---je n'ai pas essayer Clang---, voici mes questions:
-
Est-il légal d'ajouter une spécialisation à l'espace de noms
std
? J'ai des sentiments mitigés à ce sujet. -
Qui de la
std::hash<X>::operator()
versions, le cas échéant, est compatible avec le C++11? -
Est-il un portable moyen de le faire?
- Avec gcc 4.7.2, j'ai dû fournir un mondial
operator==(const Key, const Key)
Vous devez vous connecter pour publier un commentaire.
Vous sont expressément autorisés et encouragés à ajouter spécialisations à l'espace de noms
std
*. La bonne (et, fondamentalement, la seule façon) pour ajouter une fonction de hachage est-ce:(Parmi les plus populaires, les spécialisations que vous pourriez envisager de soutenir sont
std::less
,std::equal_to
etstd::swap
.)*) tant que l'un des types définis par l'utilisateur, je suppose.
unorder_map<eltype, hash, equality>
au lieu de cela, pour éviter de ruiner la journée de quelqu'un avec un drôle d'ADL d'affaires. (Modifier Pete Becker du conseil sur ce sujet)operator==
.) Ma philosophie est que si la fonction est naturel, et essentiellement de la seule "correcte" (comme lexicographique paire de comparaison), puis-je l'ajouter àstd
. Si c'est quelque chose de particulier (comme la paire non ordonnée de comparaison), puis-je le faire spécifiques à un type de conteneur.size_t operator()(const Foo & x) const
.const
modificateur de la méthode. Merci!hash
, mais aussi toutes sortes de traits...allocator_traits
,pointer_traits
,iterator_traits
...Mon pari serait sur la table de Hachage argument de modèle pour la unordered_map/unorder_set/... classes:
Bien sûr
struct Xhasher { size_t operator(const X&) const; };
)std::hash<X>()
-
std::hash
est toujours la plus belle façon de sortir 🙂char*
!hash
spécialisation interfère via ADL? Je veux dire, c'est tout à fait plausible, mais j'ai un moment difficile à venir avec un problème de cas.std::unordered_map<Whatever, Xunset>
et il ne fonctionne pas parce que votreXunset
hasher type n'est pas par défaut constructible.@Kerrek SB a couvert 1) et 3).
2) Même si g++ et VC10 déclarer
std::hash<T>::operator()
avec des signatures différentes, les deux implémentations de la bibliothèque sont conformes à la Norme.La Norme ne précise pas les membres de
std::hash<T>
. Il dit seulement que chaque spécialisation doit respecter les mêmes "Hash" les exigences requises pour la deuxième argument de modèle destd::unordered_set
et ainsi de suite. À savoir:H
est un objet de fonction, avec au moins un type d'argumentKey
.H
la copie est constructible.H
est destructible.h
est une expression de typeH
ouconst H
, etk
est une expression d'un type convertible (éventuellementconst
)Key
, puish(k)
est une expression valide de typesize_t
.h
est une expression de typeH
ouconst H
, etu
est une lvalue de typeKey
, puish(u)
est une expression valide de typesize_t
qui ne modifie pasu
.std::hash<X>::operator()
plutôt questd::hash<X>
dans son ensemble, et la signature destd::hash<T>::operator()
la mise en œuvre est définie.