J'essaie de calculer la longueur d'une chaîne littérale au moment de la compilation. Pour ce faire, j'utilise le code suivant:
#include <cstdio>
int constexpr length(const char* str)
{
return *str ? 1 + length(str + 1) : 0;
}
int main()
{
printf("%d %d", length("abcd"), length("abcdefgh"));
}
Tout fonctionne comme prévu, le programme imprime 4 et 8. Le code assembleur généré par clang montre que les résultats sont calculés au moment de la compilation:
0x100000f5e: leaq 0x35(%rip), %rdi ; "%d %d"
0x100000f65: movl $0x4, %esi
0x100000f6a: movl $0x8, %edx
0x100000f6f: xorl %eax, %eax
0x100000f71: callq 0x100000f7a ; symbol stub for: printf
Ma question: est-il garanti par la norme que la length
fonction sera évaluée lors de la compilation?
Si cela est vrai, la porte pour les calculs de littéraux de chaîne au moment de la compilation vient de s'ouvrir pour moi ... par exemple, je peux calculer des hachages au moment de la compilation et bien d'autres ...
<cstdio>
puis appeler::printf
n'est pas portable. La norme exige seulement<cstdio>
de fournirstd::printf
.printf
peut conduire à beaucoup moins de code à traiter.Réponses:
Les expressions constantes ne sont pas garanties pour être évaluées au moment de la compilation, nous n'avons qu'une citation non normative du projet de section standard C ++
5.19
Expressions constantes qui dit ceci:Vous pouvez affecter le résultat à une
constexpr
variable pour être sûr qu'il est évalué au moment de la compilation, nous pouvons le voir à partir de la référence C ++ 11 de Bjarne Stroustrup qui dit (c'est moi qui souligne ):Par exemple:
Bjarne Stroustrup donne un résumé du moment où nous pouvons assurer l'évaluation du temps de compilation dans cette entrée de blog isocpp et dit:
Donc, cela décrit deux cas où il devrait être évalué au moment de la compilation:
shall be ... converted constant expression
oushall be ... constant expression
est utilisée, comme un tableau lié.constexpr
comme je l'ai décrit ci-dessus.la source
constexpr int x = 5;
, observez qu'il n'a pas besoin de la valeur au moment de la compilation (en supposant qu'elle ne soit pas utilisée comme paramètre de modèle ou quoi que ce soit) et émet en fait code qui calcule la valeur initiale au moment de l'exécution en utilisant 5 valeurs immédiates de 1 et 4 opérations d'addition. Un exemple plus réaliste: le compilateur peut atteindre une limite de récursivité et reporter le calcul jusqu'à l'exécution. À moins que vous ne fassiez quelque chose qui force le compilateur à utiliser réellement la valeur, «garanti d'être évalué au moment de la compilation» est un problème de QOI.constexpr
calcul par pur mal. Il est même gratuit d'attendre 1 seconde par personnage dans une ligne de source donnée, ou de prendre une ligne de source donnée et de l'utiliser pour semer une position d'échecs, puis de jouer des deux côtés pour déterminer qui a gagné.Il est vraiment facile de savoir si un appel à une
constexpr
fonction aboutit à une expression constante de base ou s'il est simplement optimisé:Utilisez-le dans un contexte où une expression constante est requise.
la source
-pedantic
, si vous utilisez gcc. Sinon, vous n'obtenez aucun avertissement ni erreurenum { Whatever = length("str") }
?static_assert(length("str") == 3, "");
constexpr auto test = /*...*/;
est probablement la plus générale et la plus simple.Juste une note, que les compilateurs modernes (comme gcc-4.x) le font
strlen
pour les chaînes littérales au moment de la compilation car il est normalement défini comme une fonction intrinsèque . Sans optimisations activées. Bien que le résultat ne soit pas une constante de temps de compilation.Par exemple:
Résulte en:
la source
strlen
c'est une fonction intégrée, si nous l'utilisons,-fno-builtins
il revient à l'appeler au moment de l'exécution, regardez-le en directstrlen
estconstexpr
pour moi, même avec-fno-nonansi-builtins
(il semble-fno-builtins
qu'il n'existe plus dans g ++). Je dis "constexpr", car je peux faire çatemplate<int> void foo();
etfoo<strlen("hi")>();
g ++ - 4.8.4Permettez-moi de proposer une autre fonction qui calcule la longueur d'une chaîne au moment de la compilation sans être récursive.
Jetez un œil à cet exemple de code sur ideone .
la source
char temp[256]; sprintf(temp, "%u", 2); if(1 != length(temp)) printf("Your solution doesn't work");
ideone.com/IfKUHVIl n'y a aucune garantie qu'une
constexpr
fonction est évaluée au moment de la compilation, bien que tout compilateur raisonnable le fasse aux niveaux d'optimisation appropriés activés. D'un autre côté, les paramètres du modèle doivent être évalués au moment de la compilation.J'ai utilisé l'astuce suivante pour forcer l'évaluation au moment de la compilation. Malheureusement, cela ne fonctionne qu'avec des valeurs intégrales (c'est-à-dire pas avec des valeurs à virgule flottante).
Maintenant, si tu écris
vous pouvez être sûr que l'
if
instruction est une constante de compilation sans surcharge au moment de l'exécution.la source
len
être desconstexpr
moyenslength
doit de toute façon être évalué au moment de la compilation.if
condition (où il était essentiel que le compilateur élimine le code mort) pour laquelle j'ai initialement utilisé l'astuce.Une brève explication de l'entrée de Wikipédia sur les expressions constantes généralisées :
Le fait d'avoir le
constexpr
mot - clé avant une définition de fonction indique au compilateur de vérifier si ces limitations sont respectées. Si oui et que la fonction est appelée avec une constante, la valeur renvoyée est garantie constante et peut donc être utilisée partout où une expression constante est requise.la source