Ich habe eine constexpr-Funktion wie folgt definiert:
%Vor%Und das ist was in der Hauptfunktion:
%Vor%Das Programm wurde unter OS X 10.8 mit dem Kommando clang ++ kompiliert. Ich war überrascht, dass der Compiler keine Fehlermeldung über foo (i) erzeugte, die kein konstanter Ausdruck war, und das kompilierte Programm funktionierte wirklich gut. Warum?
Die Definition von constexpr
-Funktionen in C ++ ist so, dass die Funktion garantiert einen konstanten Ausdruck erzeugen kann, wenn sie so aufgerufen wird, dass nur konstante Ausdrücke in der Auswertung verwendet werden. Ob die Auswertung während der Kompilierung oder zur Laufzeit erfolgt, wenn das Ergebnis nicht in constexpr
verwendet wird, wird jedoch nicht angegeben (siehe auch diese Antwort ). Wenn Sie nicht konstante Ausdrücke an ein constexpr
übergeben, erhalten Sie möglicherweise keinen konstanten Ausdruck.
Der obige Code sollte jedoch nicht kompiliert werden, da i
kein konstanter Ausdruck ist, der eindeutig von foo()
verwendet wird, um ein Ergebnis zu erzeugen, und er wird dann als Array-Dimension verwendet. Es scheint, clang implementiert C-style Arrays variabler Länge, da es die folgende Warnung für mich erzeugt:
Ein besserer Test, um zu sehen, ob etwas tatsächlich ein konstanter Ausdruck ist, besteht darin, ihn zu verwenden, um den Wert von constexpr
zu initialisieren, z.B.:
Ich habe den Code oben verwendet (mit "using namespace std;" hinzugefügt) und hatte keine Fehler beim Kompilieren mit "g ++ -std = c ++ 11 code.cc" (siehe unten für eine Referenzen, die dies qualifiziert Code) Hier ist der Code und die Ausgabe:
%Vor% Betrachten Sie nun die Referenz Ссылка . Dort steht: "... Eine constexpr-Funktion ist eine, deren Rückgabewert kann bei der Kompilierung berechnet werden, wenn der Code es erfordert.Eine constexpr-Funktion muss nur literale Typen akzeptieren und zurückgeben.Wenn ihre Argumente conexpr-Werte sind, benötigt der Code den Rückgabewert zur Kompilierzeit, beispielsweise um eine constexpr-Variable zu initialisieren Wenn Sie ein non-type Template-Argument angeben, erzeugt es eine Kompilierzeitkonstante.Wenn es mit nicht-constexpr-Argumenten aufgerufen wird oder wenn sein Wert zur Kompilierzeit nicht benötigt wird, erzeugt es zur Laufzeit einen Wert wie eine reguläre Funktion strong> Durch dieses duale Verhalten müssen Sie keine constexpr- und non-consxpr-Versionen derselben Funktion schreiben. ) "
Es gibt als gültiges Beispiel:
Dies ist eine alte Frage, aber es ist das erste Ergebnis einer Google-Suche nach der VS-Fehlermeldung "constexpr function return ist nicht konstant". Und obwohl es meiner Situation nicht weiterhilft, dachte ich, ich würde meine zwei Cent in ... setzen.
Während Dietmar eine gute Erklärung für constexpr gibt, und obwohl der Fehler sofort erkannt werden sollte (wie bei der -pedantischen Flagge), sieht dieser Code so aus, als ob er unter einer Compiler-Optimierung leidet.
Der Wert i wird auf 2 gesetzt, und für die Dauer des Programms ändere ich nie. Der Compiler hat das wahrscheinlich bemerkt und die Variable als eine Konstante optimiert (indem er einfach alle Referenzen auf die Variable i auf die Konstante 2 ... ersetzt hat, bevor dieser Parameter auf die Funktion angewendet wurde) und so einen conexpr-Aufruf für foo () erzeugt >
Ich wette, wenn Sie sich die Disassemblierung ansehen würden, würden Sie sehen, dass Aufrufe von foo (i) durch den konstanten Wert 4 ersetzt wurden - da dies der einzige mögliche Rückgabewert für einen Aufruf dieser Funktion während der Ausführung des Programms ist.
Die Verwendung des Flags -pedantic zwingt den Compiler, das Programm von der strengsten Warte aus zu analysieren (wahrscheinlich vor allen Optimierungen) und fängt so den Fehler ab.