J'ai lu à quelques endroits différents qu'en utilisant les nouveaux littéraux de chaîne de C ++ 11, il pourrait être possible de calculer le hachage d'une chaîne au moment de la compilation. Cependant, personne ne semble prêt à sortir et à dire que ce sera possible ou comment cela se ferait.
- Est-ce possible?
- À quoi ressemblerait l'opérateur?
Je suis particulièrement intéressé par des cas d'utilisation comme celui-ci.
void foo( const std::string& value )
{
switch( std::hash(value) )
{
case "one"_hash: one(); break;
case "two"_hash: two(); break;
/*many more cases*/
default: other(); break;
}
}
Remarque: la fonction de hachage au moment de la compilation n'a pas besoin d'être exactement telle que je l'ai écrite. J'ai fait de mon mieux pour deviner à quoi ressemblerait la solution finale, mais meta_hash<"string"_meta>::value
pourrait aussi être une solution viable.
c++
metaprogramming
c++11
hash
code_deft
la source
la source
Réponses:
C'est un peu tard, mais j'ai réussi à implémenter une fonction CRC32 à la compilation avec l'utilisation de
constexpr
. Le problème avec cela est qu'au moment de la rédaction de cet article, il ne fonctionne qu'avec GCC et non avec le compilateur MSVC ou Intel.Voici l'extrait de code:
CrcVal01
est égal à 0x335CC04AJ'espère que ceci vous aidera!
la source
constexpr
n'est pas disponible dans VS2013, sauf en novembre 2013 CTP blogs.msdn.com/b/vcblog/archive/2013/11/18/…Au moins d'après ma lecture des §7.1.5 / 3 et §5.19, ce qui suit pourrait être légitime:
Cela semble suivre les règles de base du §7.1.5 / 3:
On se demande si les
*input
s impliquent une conversion illégale de lvalue en rvalue, et je ne suis pas sûr de comprendre les règles du §5.19 / 2/6/2 1 et du §4.1 pour être sûr de cela.D'un point de vue pratique, ce code est accepté par (pour un exemple) g ++, au moins aussi loin que g ++ 4.7.1.
L'utilisation serait quelque chose comme:
Pour vous conformer aux exigences du §5.19 / 2/6/2, vous devrez peut-être faire quelque chose comme ceci:
la source
constexpr
, 2: Vous n'avez pas de condition d'arrêt (où*input == nullptr
) et si je comprends bien,constexpr
vous ne pouvez pas en avoir.(unsigned)-1
s'il y en a; et renvoie 1 pour toutes les autres chaînes. Réécrire avec un opérateur conditionnel ternaire?Il s'agit d'une tentative de résoudre le problème du PO aussi exactement que possible.
exemple en direct .
Notez la différence principale -
std::hash
ne peut pas être utilisée, car nous n'avons pas de contrôle surstd::hash
l'algorithme de s, et nous devons le réimplémenter en tant queconstexpr
afin de l'évaluer au moment de la compilation. De plus, il n'y a pas de hachage "transparent"std
, vous ne pouvez donc pas (sans créer astd::string
) hacher un tampon de caractères bruts en tant que fichierstd::string
.J'ai collé le
std::string
hachage personnalisé (avecconst char*
prise en charge transparente ) dans unmy_hash
espace de noms, vous pouvez donc le stocker dans unstd::unordered_map
si vous avez besoin de cohérence.Basé sur l'excellente réponse de @ JerryCoffin et le fil de commentaires ci-dessous, mais avec une tentative de l'écrire avec les meilleures pratiques actuelles de C ++ 11 (au lieu de les anticiper!).
Notez que l'utilisation d'un "hachage brut" pour une
switch
instructioncase
est dangereuse. Vous voudrez faire une==
comparaison par la suite pour confirmer que cela a fonctionné.la source
Cet extrait est basé sur celui de Clement JACOB. Mais fonctionne aussi avec clang. Et cela devrait être plus rapide à la compilation (il n'a qu'un seul appel récursif, pas deux comme dans le post original).
Voir la preuve de concept ici
la source
Notez que le formulaire présenté ici n'a pas été accepté dans la norme, comme indiqué ci-dessous.
Le traitement des chaînes de temps de compilation est supposé devenir possible grâce aux littéraux définis par l' utilisateur proposés dans N2765 .
Comme je l'ai déjà mentionné, je ne connais aucun compilateur qui l'implémente actuellement et sans le support du compilateur, il ne peut y avoir que des suppositions.
Aux §2.13.7.3 et 4 du projet, nous avons ce qui suit:
Combinez cela avec
constexpr
et nous devrions avoir un traitement de chaîne de compilation.mise à jour: j'ai oublié que je lisais le mauvais paragraphe, ce formulaire est autorisé pour les littéraux entiers définis par l'utilisateur et les littéraux flottants, mais apparemment pas pour les littéraux-chaîne (§2.13.7.5).
Cette partie de la proposition ne semble pas avoir été acceptée.
Cela étant dit, avec mon aperçu limité de C ++ 0x, cela pourrait ressembler à quelque chose comme ça (j'ai probablement eu un problème):
Si l' approche Jerrys fonctionne, les éléments suivants devraient cependant fonctionner:
la source
constexpr
littéraux définis par l'utilisateur. Je ne suis pas sûr que vous puissiez utiliser une chaîne littérale comme paramètre de modèle, n'ont-ils pas une liaison statique? (ils le font au moins en C ++ 98 et sont donc verboten comme paramètres de modèle).operator ""_hash
fonctionne pour moi dans Xcode 5.0.2.Une autre solution basée sur celle de Clement JACOB, utilisant C ++ 11 constexpr (pas le C ++ 14 étendu) mais n'ayant qu'une seule récursivité.
Quelques explications
combine_crc32
nous permet de stocker le résultat d'une récursion sous une variablepart
et de l'utiliser deux fois. Cette fonction est une solution pour la limitation C ++ 11 interdisant les déclarations de variables locales.ctcrc32
fonction attend un littéral de chaîne, qui est passé en tant queconst char (&)[len]
. De cette façon, nous pouvons obtenir la longueur de la chaîne en tant que paramètre de modèle et ne pas avoir à compter sur des macros.la source
Ce qui suit fonctionne dans GCC 4.6.1, et vous pouvez utiliser l'un
hash
ou l' autre despack
blocs de commutation.GCC apparemment (?) Ne permet pas les appels récursifs où nous passons
s+1
avecs
un pointeur, c'est pourquoi j'utilise laoff
variable.la source
Si vous avez un compilateur c ++ 17 et string_view, cela devient trivial, écrivez simplement la version normale:
la source
crc32("mystring")
(généralement VS a tendance à le faire). L'astuce pour contourner ce problème consiste à créer une variable constexpr qui dépend de l'évaluation de la compilation de votre crc32. Typiquementconstexpr uint32_t val = crc32("mystring");
Voici une autre implémentation C ++ 11 (basée sur la réponse @ CygnusX1), qui fonctionne à la fois avec les tableaux de caractères constexpr et les chaînes d'exécution:
Vous avez besoin
str.size() + 1
parce quelen
dans la deuxième surcharge eststrlen(str) + 1
due au caractère nul à la fin.Je n'ai pas ajouté de surcharge pour
const char *
car cela gâche la deuxième surcharge - Vous pouvez facilement ajouter des surcharges pourconst char *, size_t
oustd::string_view
.la source
C'est une bonne question.
Sur la base de la réponse de Jerry Coffin, j'en ai créé un autre compatible avec std :: hash de Visual Studio 2017.
https://github.com/manuelgustavo/cx_hash
la source
Il me manquait toujours une variante crc32-littérale (ce qui n'est pas possible avec les modèles), voici donc ma suggestion basée sur CygnusX1 . Avez-vous fait des tests, n'hésitez pas à donner votre avis.
Testet sur MSVC.
PS: Je déteste chercher des trucs supplémentaires ailleurs, alors j'ai copié le tableau CRC au bas de ma réponse.
Alternative avec algorithmn de Dan Bernstein (djb2) (réponses combinées de Jerry Coffin + Georg Fritzsche )
Tableau CRC32:
la source