Ich versuche, die Länge eines String-Literals zur Kompilierungszeit zu berechnen. Dazu verwende ich folgenden Code:
#include <cstdio>
int constexpr length(const char* str)
{
return *str ? 1 + length(str + 1) : 0;
}
int main()
{
printf("%d %d", length("abcd"), length("abcdefgh"));
}
Alles funktioniert wie erwartet, das Programm druckt 4 und 8. Der durch clang generierte Assembler-Code zeigt, dass die Ergebnisse zur Kompilierungszeit berechnet werden:
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
Meine Frage: length
Wird durch den Standard garantiert, dass die Kompilierungszeit der Funktion ausgewertet wird?
Wenn dies zutrifft, hat sich mir gerade die Tür für Berechnungen von Zeichenfolgenliteralen zur Kompilierungszeit geöffnet ... zum Beispiel kann ich Hashes zur Kompilierungszeit berechnen und vieles mehr ...
<cstdio>
und anschließender Anrufe,::printf
ist nicht portabel. Der Standard muss nur<cstdio>
bereitstellenstd::printf
.printf
was dazu führen kann, dass deutlich weniger Code bearbeitet werden muss .Antworten:
Konstante Ausdrücke sind nicht garantiert bei der Kompilierung ausgewertet werden, haben wir nur ein nicht-normatives Zitat aus Entwurf C ++ Standard Abschnitt
5.19
Konstante Ausdrücke , der dies sagt aber:Sie können das Ergebnis einer
constexpr
Variablen zuweisen , um sicherzustellen, dass es zur Kompilierungszeit ausgewertet wird. Dies geht aus der C ++ 11-Referenz von Bjarne Stroustrup hervor, in der es heißt ( Hervorhebung von mir ):Beispielsweise:
Bjarne Stroustrup gibt in diesem isocpp-Blogeintrag eine Zusammenfassung darüber, wann wir die Bewertung der Kompilierungszeit sicherstellen können, und sagt:
Dies beschreibt also zwei Fälle, in denen es zur Kompilierungszeit ausgewertet werden sollte:
shall be ... converted constant expression
odershall be ... constant expression
verwendet wird, z. B. an ein gebundenes Array.constexpr
wie oben beschrieben zu initialisieren .quelle
constexpr int x = 5;
. Beachten Sie, dass der Wert zur Kompilierungszeit nicht erforderlich ist (vorausgesetzt, er wird nicht als Vorlagenparameter verwendet oder so weiter) und tatsächlich emittiert Code, der den Anfangswert zur Laufzeit unter Verwendung von 5 Sofortwerten von 1 und 4 Additionsoperationen berechnet. Ein realistischeres Beispiel: Der Compiler erreicht möglicherweise ein Rekursionslimit und verschiebt die Berechnung bis zur Laufzeit. Sofern Sie nichts tun, was den Compiler dazu zwingt, den Wert tatsächlich zu verwenden, ist "garantiert zur Kompilierungszeit ausgewertet" ein QOI-Problem.constexpr
Berechnung einfach sinnlos aus dem Bösen heraus. Es ist sogar kostenlos, 1 Sekunde pro Charakter in einer bestimmten Quellzeile zu warten oder eine bestimmte Quellzeile zu nehmen und damit eine Schachposition zu setzen und dann beide Seiten zu spielen, um festzustellen, wer gewonnen hat.Es ist wirklich einfach herauszufinden, ob ein Aufruf einer
constexpr
Funktion zu einem konstanten Kernausdruck führt oder lediglich optimiert wird:Verwenden Sie es in einem Kontext, in dem ein konstanter Ausdruck erforderlich ist.
quelle
-pedantic
, wenn Sie gcc verwenden. Andernfalls erhalten Sie keine Warnungen und Fehlerenum { Whatever = length("str") }
?static_assert(length("str") == 3, "");
constexpr auto test = /*...*/;
ist wahrscheinlich die allgemeinste und einfachste.Nur eine Anmerkung, die moderne Compiler (wie gcc-4.x)
strlen
zur Kompilierungszeit für String-Literale verwenden, da sie normalerweise als intrinsische Funktion definiert sind . Ohne aktivierte Optimierungen. Obwohl das Ergebnis keine Kompilierungszeitkonstante ist.Z.B:
Ergebnisse in:
quelle
strlen
es sich um eine integrierte Funktion handelt. Wenn wir sie verwenden-fno-builtins
, um sie zur Laufzeit aufzurufen, sehen Sie sie livestrlen
istconstexpr
für mich auch mit-fno-nonansi-builtins
(scheint-fno-builtins
in g ++ nicht mehr zu existieren). Ich sage "constexpr", weil ich dies tun kanntemplate<int> void foo();
undfoo<strlen("hi")>();
g ++ - 4.8.4Lassen Sie mich eine andere Funktion vorschlagen, die die Länge eines Strings zur Kompilierungszeit berechnet, ohne rekursiv zu sein.
Schauen Sie sich diesen Beispielcode bei ideone an .
quelle
char temp[256]; sprintf(temp, "%u", 2); if(1 != length(temp)) printf("Your solution doesn't work");
ideone.com/IfKUHVEs gibt keine Garantie dafür, dass eine
constexpr
Funktion zur Kompilierungszeit ausgewertet wird, obwohl jeder vernünftige Compiler dies bei entsprechenden aktivierten Optimierungsstufen tut. Auf der anderen Seite, Template - Parameter müssen zur Compile-Zeit ausgewertet werden.Ich habe den folgenden Trick verwendet, um die Auswertung zur Kompilierungszeit zu erzwingen. Leider funktioniert es nur mit Integralwerten (dh nicht mit Gleitkommawerten).
Nun, wenn Sie schreiben
Sie können sicher sein, dass die
if
Anweisung eine Konstante zur Kompilierungszeit ohne Laufzeitaufwand ist.quelle
len
seinconstexpr
Mittellength
muss sowieso bei der Kompilierung ausgewertet werden.if
Bedingung (bei der es wichtig war, dass der Compiler die Beseitigung von totem Code durchführte), für die ich ursprünglich den Trick verwendet habe.Eine kurze Erklärung aus dem Wikipedia-Eintrag zu verallgemeinerten konstanten Ausdrücken :
Wenn das
constexpr
Schlüsselwort vor einer Funktionsdefinition steht, wird der Compiler angewiesen, zu überprüfen, ob diese Einschränkungen erfüllt sind. Wenn ja und die Funktion mit einer Konstanten aufgerufen wird, ist der zurückgegebene Wert garantiert konstant und kann daher überall dort verwendet werden, wo ein konstanter Ausdruck erforderlich ist.quelle