2013-06-08 10 views
11

A constexpr Funktion muss eine return-Anweisung besteht nur und jedes Argument sollte zum Zeitpunkt der Kompilierung bekannt sein:conexpr - warum nur eine Rückmeldung?

// constexpr functions use recursion rather than iteration 
constexpr int factorial(int n) 
{ 
    return n <= 1 ? 1 : (n * factorial(n-1)); 
} 

Warum gerade die return-Anweisung? Ich meine, warum ist das falsch?

// constexpr functions use recursion rather than iteration 
constexpr int factorial(int n) 
{ 
    int a = 222; //another variable 
    return n <= 1 ? 1 : (n * factorial(n-1)); 
} 
+7

Ich vermute, es ist nur ein Mittel, um es für Compiler-Implementierungen einfach zu halten. – juanchopanza

+10

Weil der Standard dies sagt. Die Berücksichtigung allgemeinerer Funktionen würde die Lebensdauer von Compiler-Schreibern erheblich verkomplizieren (C++ 14 hebt jedoch einige dieser Einschränkungen auf) –

+3

Da das Zulassen von Variablen bedeuten würde, dass viele andere (kompliziertere) Einschränkungen hinzugefügt werden müssten. Also haben sie es einfach gehalten für ihre Einführung. Es gibt sowieso Möglichkeiten, die Funktion "constexpr" beispielsweise von einer anderen zu nennen. – Dave

Antwort

6

Es vereinfacht die Implementierung, wie Andy Prowl sagt. Das beantwortet möglicherweise "Warum", aber es sagt nicht, wie es das macht.

Eine Funktion mit nur einem Rückgabewert und speziell ohne lokale Variablen ist eine spezielle Situation für einen Compiler. Diese Funktion besteht nun aus einem einzigen Ausdruck: Der AST der Funktion muss nur eine einzige Wurzel haben. Dieser Mangel an Variablen bedeutet, dass dieser Ausdruck ohne eine vollständige virtuelle Maschine ausgewertet werden kann, um sie zu verarbeiten, stattdessen kann ein einfacher Baumausdruck-Evaluator verwendet werden. Aus verschiedenen Gründen hat der Compiler wahrscheinlich bereits einen solchen Evaluator oder könnte einen relativ leicht erstellen (es wird ein Tree-Simplification-Pass).

Zu wissen, dass innerhalb des Ausdrucks nur constexpr verwendet wird, bietet auch eine wichtige Vereinfachung. Dies garantiert, dass jeder Knoten in der Funktion AST die gleichen Eigenschaften hat, selbst wenn es sich um einen Funktionsaufruf handelt. Der gesamte constexpr Mechanismus ist dann eine verallgemeinerte Form der Const-Faltung. Und obwohl es im Compiler nicht immer auf dieser hohen Ebene gemacht wird, stellt es sicher, dass es ohne großen Aufwand (im Vergleich zu einer vollständigen VM) implementiert werden kann.

Zurück zur Frage "Warum". Die Beschränkung wird hauptsächlich durch Ressourcenbeschränkungen bei den Anbietern verursacht. Dieses Merkmal ist, wie angegeben, kein großer Aufwand, und daher können die Anbieter es in einer angemessenen Zeitspanne tatsächlich implementieren. Wenn es keine solchen Einschränkungen gäbe, insbesondere wenn lokale Variablen zugelassen würden, würde dies den Arbeitsaufwand erheblich erhöhen. Aus Sicht des Anwenders (uns, den Programmierern) sind die Einschränkungen jedoch völlig willkürlich.

+0

Schöne Antwort. "constexpr" fordert den Compiler tatsächlich dazu auf, es zu interpretieren (anstatt es zu kompilieren), so dass das Streben nach Einfachheit verständlich ist. Eine nette Ergänzung wäre allerdings 'static if' (nützlich für' constexpr', nicht nur für Templates), über welchen Status ich mich jetzt nicht sicher bin. – eudoxos

+0

Ich denke, es ist auch aus einem anderen Grund. Sie können keine unendlichen Schleifen haben, und inverse rekursive Aufrufe können einfach durch Feststellen einer Rekursionsgrenze erkannt werden. Jede Änderung an constexpr, die mehr Dinge erlaubt, würde auch komplexere Invarianten implizieren, die Benutzer beachten müssen, um Code kompilieren zu können, ohne zu wandern, warum sie nicht kompiliert wird. Ich bezweifle auch, dass Sie tatsächlich auch "beweisen" müssen, dass consExpr funktioniert, und es wäre auch aus theoretischer Sicht schwierig oder unmöglich, es für willkürlichen Code zu testen. – GameDeveloper

13

Warum:

Da constexpr ist ein ziemlich neues und radikales Konzept in C++ 11 und es ist schwierig, einen großen Sprachstandard zu etwas völlig Neues zu überführen. Konservatismusregeln.

Für C++ 1y (derzeit auf C++ 14 ausgerichtet), ist Ihr Beispiel legal. Die Spitze des Kofferraumklangs implementiert sie bereits unter der Flagge -std=c++1y.