2017-02-08 6 views
16

Ich bin wirklich verwirrt über ein constexpr Konzept, wie ich gelesen habe constexpr wird zur Kompilierzeit ausgewertet, so ist es nützlich für die Leistungsoptimierung gegenüber normalen const.Was ist Constexpr in C++?

constexpr int i = 0; 
constexpr int& ri = i; 

Der obige Code gibt einen Fehler „ungültige Initialisierung einer Referenz vom Typ‚int &‘aus Ausdruck vom Typ‚const int‘“, warum?

Auch der nächste Code hat einen Fehler:

constexpr int i = 0; 
constexpr int* ri = &i; 

Wenn ich das constexpr Schlüsselwort mit const ersetzt, die alle richtig oben gearbeitet.

+0

Mögliche doppelte: http://stackoverflow.com/questions/13346879/const-vs-constexpr-on-variables –

+1

Sie vergessen haben, const Qualifier 'constexpr int const & ri = i;'. 'constexpr int i = 0;' deklariere auch 'i' als const ... [demo] (http://melpon.org/wandbox/permlink/2oc2VMdtymZ93ANa) –

+0

Mögliche Duplikate von [const vs conexpr auf Variablen] (http: //stackoverflow.com/questions/13346879/const-vs-contexpr-on-variables) – Swapnil

Antwort

6

Re

if I replaced the constexpr word with const all above worked correctly."

A const int* bedeutet im Wesentlichen (const int)*, mit der Ausnahme, dass Sie nicht verwenden können, Klammern auf diese Weise. A constexpr int* bedeutet constepxr (int*) (auch zu beachten).

Dies ist, weil constexpr nicht Teil des Typs ist, können Sie nicht den Typ constexpr int, sagen, während const Teil des Typs ist.

Statt

constexpr int i = 0; 
constexpr int& ri = i; 

, die eine constexpr Bezug zu erklären versucht const nicht, schreiben Sie einfach

constexpr int i = 0; 
constexpr int const& ri = i; 

Sie können die rückwärts gelesen als ri ein Verweis auf eine constint ist, die ist constexpr (zur Kompilierzeit ausgewertet).


Nachtrag:

Es ¹appears, dass C++ 14 lokale nicht staticconstexpr Objekte erfordert automatische Speicherdauer, die für die Optimierung as-if Regel Modulo zu haben.

dafür zu sorgen, das heißt den Code portabel zwischen Compiler zu machen, wenn die oben genannten Erklärungen lokal in einer Funktion erscheinen, fügen Sie static für das Objekt statische Speicherdauer, um sicherzustellen, dass man bezieht sich auf:

void oops() 
{ 
    static constexpr int i = 0;  // Necessary with some compilers. 
    constexpr int const& ri = i; 
} 

Ansonsten kann es nicht mit zb kompilieren g ++, und es ist wahrscheinlich was die C++ 14 und C++ 11 Standards erfordern, durch Weglassen geeigneter Einschränkungen auf constexpr.

Hinweise:
¹ die discussion of R. Sahu's answer See.

3

Wie Sie sagten, constexpr bei Kompilierung ausgewertet. Der Wert muss also beim Übersetzen auswertbar sein.

Zum Beispiel:

constexpr int i = 0; 
constexpr int& ri = i; 

Für die erste Zeile, 0 ist auswertbaren beim Kompilieren, dessen Wert 0

Aber für die zweite Linie ist, muss Compiler-Adresse des i die Zuordnung zu tun, das ist zur Laufzeit ermittelt. Also wird diese Zeile fehlschlagen.

+0

Wird ein Constexpr nur zur Leistungsoptimierung im Vergleich zu einem Const verwendet? –

+1

@BassamNajeeb Es kann verwendet werden, um Makros und hartcodierte Literale zu ersetzen. Beispielsweise können Sie Makros und Literale in "conexpr" -Funktionen einbinden und ihnen einen aussagekräftigen Namen geben. –

1

Hier sind meine 2 Cent:

Die constexpr Feature Berechnung definiert, die während der Kompilierung geschieht. Vernünftige Frage:

  • Macht es Sinn, zu ermöglichen jede Berechnung?

vernünftige Antwort:

  • Keine, weil dies eine Menge von Maschinen erfordern würde, Ressourcen, usw. direkt in den Compiler, während es keine direkte Notwendigkeit dafür.

Aufgrund dieser Norm erlaubt ziemlich begrenzten Satz von Funktionen innerhalb der constexpr Code. Man kann argumentieren warum genau dieses Set und nicht etwas mehr? Nun, später kann sich der Standard weiterentwickeln und mehr erlauben.

13
constexpr int i = 0; 
constexpr int * ri = &i; 

Die zweite Zeile ist ein Problem, weil der Zeiger auf ein Objekt zeigt const nicht. Der Zeiger selbst ist const.

Mit

constexpr int i = 0; 
constexpr int const * ri = &i; 

löst dieses Problem. Dies ist jedoch immer noch ein Problem, wenn die Variablen in einem Funktionsumfang definiert sind.

constexpr int i = 0; 
constexpr int const* ri = &i; 

int main() {} 

ist ein gültiges Programm.

void foo() 
{ 
    constexpr int i = 0; 
    constexpr int const* ri = &i; 
} 

int main() {} 

ist kein gültiges Programm.

Hier ist, was der C++ 11-Standard über Adresse konstanter Ausdruck zu sagen hat:

5.19 Constant expressions

3 .. An address constant expression is a prvalue core constant expression of pointer type that evaluates to the address of an object with static storage duration, to the address of a function, or to a null pointer value, or a prvalue core constant expression of type std::nullptr_t .

+0

Ich bin nicht mit dem Problem des Funktionsumfangs vertraut. Ich sehe, dass sich g ++ verhält, wie Sie angeben, aber MSVC akzeptiert diesen angeblich ungültigen Code. g ++ sagt, dass "i" nicht konstant ist, sondern seine Verwendung als Array-Größe (und nicht als VLA) erlaubt. Das ist inkonsequent. g ++ akzeptiert den Code mit 'static' hinzugefügt. Sind Sie sicher, dass Sie keine Kompilierungs-Fehler (Bug) als eine Regel der Sprache melden? Wenn es eine Regel ist, was ist es? –

+0

@ Cheersandhth.-Alf Ich denke, RSahu hat Recht, man kann keine Adresse liefern, die constexpr-Zeiger ist laufzeitabhängig. Stellen Sie sich die Situation vor, wenn das foo rekursiv aufgerufen wird. 'ri' sollte auf jeder Rekursionsebene einen anderen Wert erhalten, aber wie viele Rekursionsebenen gibt es? Es kann vom Laufzeitwert abhängen ... –

+0

@ W.F .: Ich würde nicht denken, dass dieses Argument halten würde, weil es keinen Sinn hat, "i" eine andere zur Laufzeit bestimmte Adresse zu geben, aber mit einem zur Kompilierungszeit bekannten Wert. Das ist nur Idiotie. Wenn es in der aktuellen Sprachdefinition eine solche Regel gibt, dann handelt es sich eindeutig um einen Fehler im Standard. Also interessiert mich, was die (angebliche) Regel ist. –