Sur https://en.cppreference.com/w/cpp/utility/hash il est dit que depuis C++ 17
Chaque en-tête de bibliothèque standard qui déclare le modèle std :: hash fournit des spécialisations activées de std :: hash pour std :: nullptr_t et tous les types arithmétiques non qualifiés par cv (y compris tous les types entiers étendus), tous les types d'énumération et tous les types de pointeurs.
Ainsi, un compilateur compatible C++ 17 devrait compiler ce petit programme:
#include <functional>
int main()
{
std::hash<std::nullptr_t> h;
return h(nullptr);
}
Cependant, GCC et Clang signalent tous deux une erreur indiquant que le constructeur par défaut de std::hash<std::nullptr_t>
est (implicitement) supprimé. Voir ici et ici pour le vérifier vous-même.
Visual Studio le compile. Apparemment ça revient 0
672807365
.
Q1: Est-ce que GCC et Clang manquent toujours cette fonctionnalité C++ 17, car il est vrai que ce n'est pas une priorité élevée? Ou est-ce que je manque quelque chose?
Q2: Puis-je juste me spécialiser et revenir 0
672807365
comme Visual Studio? N'aurait pas une autre valeur, par exemple certains prime, mieux vaut le combiner avec d'autres hachages?
En raison de ma connaissance limitée de l'assembleur, je pensais que Visual Studio renvoyait 0
. En fait, il revient 672807365
(la valeur dans eax
). Donc, ma deuxième question se répond essentiellement: je vais pas retourner 0
dans ma spécialisation pour contourner ce bogue.
cppreference.com a raison. Du dernier projet de norme C++:
[unord.hash]/2
Chaque spécialisation de hachage est activée ou désactivée, comme décrit ci-dessous. [...] Chaque en-tête qui déclare le hachage du modèle fournit des spécialisations activées de
hash
pournullptr_t
et tous les types d'arithmétique, d'énumération et de pointeur non qualifiés par cv.
Puisque <functional>
déclare le modèle hash
1, il doit fournir une spécialisation activée pour std::hash<std::nullptr_t>
. Votre exemple de programme doit être accepté par toute implémentation C++ 17 conforme .
C++ 17 étant encore jeune, certaines fonctionnalités subtiles peuvent manquer encore ou boguer sur les compilateurs récents. Rassurez-vous, votre MCVE est accepté par gcc et clang dans leurs branches développement/ experimental .
Nous n'avons pas pu trouver une version de développement de GCC l'acceptant cependant; c'est pourquoi un rapport de bug a été généré par Lightness Races in Orbit (voir std :: hash non implémenté ) et corrigé par - Jonathan Wakely (voir revision267845 ) (et il retourne zéro ).
Puis-je juste me spécialiser et retourner 0 comme Visual Studio?
Vous écririez du code qui présentera un comportement indéfini2. Faites-le à vos risques et périls. Documentez-le bien. Par exemple, mettez ce qui suit dans une unité de traduction séparée:
#include <functional>
#include <type_traits>
static_assert(
false == std::is_default_constructible_v<std::hash<std::nullptr_t>>,
"Explanation"
);
Cela avertira vos collègues et leur demandera de supprimer manuellement votre spécialisation de std::hash<std::nullptr_t>
plutôt que d'obtenir une méchante erreur de compilation.
1) Voir [functional.syn]
.
2) Vous êtes niquement autorisé pour spécialiser std
modèles de classe pour les types définis par programme (qui nullptr_t
n'est pas). Vous pouvez également enfreindre la règle de définition unique.