web-dev-qa-db-fra.com

GCC et Clang ne compilent pas std :: hash <std :: nullptr_t> en C ++ 17

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 0672807365.

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 0672807365 comme Visual Studio? N'aurait pas une autre valeur, par exemple certains prime, mieux vaut le combiner avec d'autres hachages?


Mettre à jour

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.

23
sebrockm

Ce programme est-il correct?

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 pour nullptr_­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 hash1, 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 .


Mais pourquoi pas?

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 ).


Comment réparer votre programme en attendant que votre implémentation soit réparée?

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.

19
YSC