boost/hanaMöglicherweise kann dieser Artikel aus der Bibliothek einige constexprProbleme aufzeigen, die Sie verwenden können constexprund wo Sie nicht können: boost.org/doc/libs/1_69_0/libs/hana/doc/html/…
Andry
@ 0x499602D2 " bedeutet einfach, dass der Wert nicht geändert werden kann " Für einen mit einem Literal initialisierten Skalar ist ein Wert, der nicht geändert werden kann, auch eine Kompilierungszeitkonstante.
Neugieriger
@curiousguy Ja, mein Kommentar war sehr stark vereinfacht. Zugegeben, ich war constexprdamals auch neu :)
0x499602D2
Antworten:
587
Grundlegende Bedeutung und Syntax
Beide Schlüsselwörter können sowohl bei der Deklaration von Objekten als auch bei Funktionen verwendet werden. Der grundlegende Unterschied bei der Anwendung auf Objekte ist folgender:
constdeklariert ein Objekt als konstant . Dies impliziert eine Garantie, dass sich der Wert dieses Objekts nach der Initialisierung nicht ändert und der Compiler diese Tatsache für Optimierungen nutzen kann. Es hilft auch zu verhindern, dass der Programmierer Code schreibt, der Objekte ändert, die nach der Initialisierung nicht geändert werden sollten.
constexprdeklariert ein Objekt als zur Verwendung in den vom Standard als konstant bezeichneten Ausdrücken geeignet . Beachten Sie jedoch, dass dies constexprnicht der einzige Weg ist, dies zu tun.
Bei der Anwendung auf Funktionen ist der grundlegende Unterschied folgender:
constkann nur für nicht statische Elementfunktionen verwendet werden, nicht für Funktionen im Allgemeinen. Es gibt eine Garantie dafür, dass die Elementfunktion keines der nicht statischen Datenelemente ändert.
constexprkann sowohl mit Member- als auch Nicht-Member-Funktionen sowie mit Konstruktoren verwendet werden. Es deklariert die Funktion für die Verwendung in konstanten Ausdrücken . Der Compiler akzeptiert es nur, wenn die Funktion bestimmte Kriterien erfüllt (7.1.5 / 3,4), vor allem (†) :
Der Funktionskörper muss nicht virtuell und äußerst einfach sein: Abgesehen von typedefs und statischen Asserts ist nur eine einzige returnAnweisung zulässig. Im Fall eines Konstruktors sind nur eine Initialisierungsliste, typedefs und statische Zusicherungen zulässig. ( = defaultund = deletesind aber auch erlaubt.)
Ab C ++ 14 sind die Regeln entspannter, was seitdem in einer constexpr-Funktion zulässig ist: asmDeklaration, eine gotoAnweisung, eine Anweisung mit einer anderen Bezeichnung als caseund default, try-block, Definition einer Variablen vom nicht-wörtlichen Typ, Definition einer Variablen mit statischer oder Thread-Speicherdauer, Definition einer Variablen, für die keine Initialisierung durchgeführt wird.
Die Argumente und der Rückgabetyp müssen Literaltypen sein (dh im Allgemeinen sehr einfache Typen, typischerweise Skalare oder Aggregate).
Konstante Ausdrücke
Wie oben erwähnt, werden constexprsowohl Objekte als auch Funktionen als für die Verwendung in konstanten Ausdrücken geeignet deklariert. Ein konstanter Ausdruck ist mehr als nur konstant:
Es kann an Orten verwendet werden, an denen eine Auswertung zur Kompilierungszeit erforderlich ist, z. B. bei Vorlagenparametern und Array-Größenangaben:
template<int N>class fixed_size_list
{/*...*/};
fixed_size_list<X> mylist;// X must be an integer constant expressionint numbers[X];// X must be an integer constant expression
Aber beachten Sie:
Das Deklarieren von etwas constexprgarantiert nicht unbedingt, dass es beim Kompilieren ausgewertet wird. Es kann für solche verwendet werden, aber es kann auch an anderen Orten verwendet werden, die zur Laufzeit ausgewertet werden.
Ein Objekt kann zur Verwendung in konstanten Ausdrücken geeignet sein, ohne deklariert zu werden constexpr. Beispiel:
int main(){constint N =3;int numbers[N]={1,2,3};// N is constant expression}
Dies ist möglich, weil Nes konstant ist und zur Deklarationszeit mit einem Literal initialisiert wird und die Kriterien für einen konstanten Ausdruck erfüllt, auch wenn er nicht deklariert ist constexpr.
Also wann muss ich eigentlich verwenden constexpr?
Ein Objekt wie Noben kann als konstanter Ausdruck verwendet werden, ohne deklariert zu werden constexpr. Dies gilt für alle Objekte, die:
const
vom Integral- oder Aufzählungstyp und
Wird zur Deklarationszeit mit einem Ausdruck initialisiert, der selbst ein konstanter Ausdruck ist
[Dies liegt an §5.19 / 2: Ein konstanter Ausdruck darf keine Unterausdrücke enthalten, die "eine Änderung von lWert zu rWert" beinhalten, es sei denn, […] ein GlWert vom Integral- oder Aufzählungstyp […] "Dank an Richard Smith für die Korrektur von my frühere Behauptung, dass dies für alle wörtlichen Typen gilt.]
Damit eine Funktion für die Verwendung in konstanten Ausdrücken geeignet ist, muss sie explizit deklariert werden constexpr. es reicht nicht aus, nur die Kriterien für Konstantausdrucksfunktionen zu erfüllen. Beispiel:
template<int N>classlist{};constexprint sqr1(int arg){return arg * arg;}int sqr2(int arg){return arg * arg;}int main(){constint X =2;list<sqr1(X)> mylist1;// OK: sqr1 is constexprlist<sqr2(X)> mylist2;// wrong: sqr2 is not constexpr}
Wann kann / soll ich beide constund constexprzusammen verwenden?
A. In Objektdeklarationen. Dies ist niemals erforderlich, wenn beide Schlüsselwörter auf dasselbe zu deklarierende Objekt verweisen. constexprimpliziert const.
constexprconstint N =5;
ist das gleiche wie
constexprint N =5;
Beachten Sie jedoch, dass es Situationen geben kann, in denen sich die Schlüsselwörter jeweils auf verschiedene Teile der Deklaration beziehen:
staticconstexprint N =3;int main(){constexprconstint*NP =&N;}
Hier NPwird als Adresskonstantenausdruck deklariert, dh als Zeiger, der selbst ein konstanter Ausdruck ist. (Dies ist möglich, wenn die Adresse durch Anwenden des Adressoperators auf einen statischen / globalen Konstantenausdruck generiert wird.) Hier sind beide constexprund consterforderlich: constexprbezieht sich immer auf den deklarierten Ausdruck (hier NP), während constauf int(er deklariert einen Zeiger-) to-const). Das Entfernen von constwürde den Ausdruck unzulässig machen (weil (a) ein Zeiger auf ein nicht konstantes Objekt kein konstanter Ausdruck sein kann und (b) &Ntatsächlich ein Zeiger auf eine Konstante ist).
B. In Mitgliedsfunktionsdeklarationen. In C ++ 11 constexprbedeutet dies const, dass dies in C ++ 14 und C ++ 17 nicht der Fall ist. Eine unter C ++ 11 deklarierte Mitgliedsfunktion als
constexprvoid f();
muss deklariert werden als
constexprvoid f()const;
unter C ++ 14, um weiterhin als constFunktion verwendbar zu sein .
IMO ist das "nicht unbedingt zur Kompilierungszeit ausgewertet" weniger hilfreich, als sie als "zur Kompilierungszeit ausgewertet" zu betrachten. Die Einschränkungen für einen konstanten Ausdruck bedeuten, dass es für einen Compiler relativ einfach wäre, ihn auszuwerten. Ein Compiler muss sich beschweren, wenn diese Einschränkungen nicht erfüllt sind. Da es keine Nebenwirkungen gibt, können Sie nie einen Unterschied feststellen, ob ein Compiler dies "bewertet" hat oder nicht.
Aschepler
10
@aschepler Sicher. Mein Hauptpunkt dort ist, dass, wenn Sie eine constexprFunktion für einen nicht konstanten Ausdruck aufrufen , z. B. eine gewöhnliche Variable, dies vollkommen legal ist und die Funktion wie jede andere Funktion verwendet wird. Es wird zur Kompilierungszeit nicht ausgewertet (da dies nicht möglich ist). Vielleicht denken Sie, dass dies offensichtlich ist - aber wenn ich feststelle, dass eine als deklarierte Funktion constexprimmer zur Kompilierungszeit ausgewertet wird, könnte sie falsch interpretiert werden.
Jogojapan
5
Ja, ich habe über constexprObjekte gesprochen, nicht über Funktionen. Ich stelle mir constexprObjekte gerne so vor, dass sie die Auswertung der Werte zur Kompilierungszeit erzwingen, und constexprFunktionen, bei denen die Funktion je nach Bedarf zur Kompilierungs- oder Laufzeit ausgewertet werden kann.
Aschepler
2
Eine Korrektur: 'const' ist nur eine Einschränkung, dass SIE den Wert einer Variablen nicht ändern können. Es gibt kein Versprechen, dass sich der Wert nicht ändert (dh von jemand anderem). Es ist eine Schreibeigenschaft, keine Leseeigenschaft.
Jared Grubb
3
Dieser Satz: Es gibt eine Garantie dafür, dass die Elementfunktion keines der nicht statischen Datenelemente ändert. vermisst ein wichtiges Detail. Als markiert gekennzeichnete Mitglieder mutablekönnen auch durch constMitgliederfunktionen geändert werden .
Omnifarious
119
constgilt für Variablen und verhindert , dass diese in Ihrem Code geändert werden.
constexprteilt dem Compiler mit, dass dieser Ausdruck zu einem Wert für die Kompilierungszeitkonstante führt , sodass er an Stellen wie Array-Längen, Zuweisen zu constVariablen usw. verwendet werden kann. Der von Oli angegebene Link enthält viele hervorragende Beispiele.
Grundsätzlich handelt es sich um zwei verschiedene Konzepte, die zusammen verwendet werden können (und sollten).
constgarantiert, dass ein Programm den Wert eines Objekts nicht ändert . Jedoch,const garantiert nicht , welche Art der Initialisierung das Objekt erfährt.
Die Funktion gibt max()lediglich einen Literalwert zurück. Da der Initialisierer jedoch ein Funktionsaufruf ist, mxwird er zur Laufzeit initialisiert. Daher können Sie es nicht als konstanten Ausdruck verwenden :
int arr[mx];// error: “constant expression required”
constexprist ein neues C ++ 11-Schlüsselwort, mit dem Sie keine Makros und fest codierten Literale erstellen müssen. Unter bestimmten Bedingungen wird auch garantiert, dass Objekte einer statischen Initialisierung unterzogen werden . Es steuert die Auswertungszeit eines Ausdrucks. Durch die Durchsetzung der Kompilierung Zeitauswertung seines Ausdrucks , constexprkönnen Sie wahre definieren konstante Ausdrücke , die für zeitkritische Anwendungen von entscheidender Bedeutung sind, Systemprogrammierung, Vorlagen und allgemein gesprochen, in jedem Code, der auf der Kompilierung Zeitkonstanten beruht.
Funktionen mit konstantem Ausdruck
Eine Funktion mit konstantem Ausdruck ist eine deklarierte Funktion constexpr. Sein Body darf nicht virtuell sein und nur aus einer einzigen return-Anweisung bestehen, abgesehen von typedefs und statischen Asserts. Die Argumente und der Rückgabewert müssen Literaltypen haben. Es kann mit Argumenten ohne konstanten Ausdruck verwendet werden, aber wenn dies erledigt ist, ist das Ergebnis kein konstanter Ausdruck.
Eine Funktion mit konstantem Ausdruck soll Makros und fest codierte Literale ersetzen, ohne die Leistung oder die Typensicherheit zu beeinträchtigen .
constexprint max(){return INT_MAX;}// OKconstexprlong long_max(){return2147483647;}// OKconstexprbool get_val(){bool res =false;return res;}// error: body is not just a return statementconstexprint square(int x){return x * x;}// OK: compile-time evaluation only if x is a constant expressionconstint res = square(5);// OK: compile-time evaluation of square(5)int y = getval();int n = square(y);// OK: runtime evaluation of square(y)
Objekte mit konstantem Ausdruck
Ein Objekt mit konstantem Ausdruck ist ein deklariertes Objekt constexpr. Es muss mit einem konstanten Ausdruck oder einem Wert initialisiert werden, der von einem Konstruktor mit konstantem Ausdruck mit Argumenten mit konstantem Ausdruck erstellt wurde.
Ein Objekt mit konstantem Ausdruck verhält sich so, als ob es deklariert worden wäre const, außer dass es vor der Verwendung initialisiert werden muss und sein Initialisierer ein konstanter Ausdruck sein muss. Folglich kann ein Objekt mit konstantem Ausdruck immer als Teil eines anderen konstanten Ausdrucks verwendet werden.
struct S
{constexprint two();// constant-expression functionprivate:staticconstexprint sz;// constant-expression object};constexprint S::sz =256;enumDataPacket{Small= S::two(),// error: S::two() called before it was definedBig=1024};constexprint S::two(){return sz*2;}constexpr S s;int arr[s.two()];// OK: s.two() called after its definition
Konstruktoren mit konstanter Expression
Ein Konstruktor mit konstantem Ausdruck ist ein deklarierter Konstruktor constexpr. Es kann eine Mitgliederinitialisierungsliste haben, aber sein Text muss leer sein, abgesehen von typedefs und statischen Asserts. Seine Argumente müssen Literaltypen haben.
Ein Konstruktor mit konstantem Ausdruck ermöglicht es dem Compiler, das Objekt zur Kompilierungszeit zu initialisieren, vorausgesetzt, die Argumente des Konstruktors sind alle konstante Ausdrücke.
struct complex
{// constant-expression constructorconstexpr complex(double r,double i): re(r), im(i){}// OK: empty body// constant-expression functionsconstexprdouble real(){return re;}constexprdouble imag(){return im;}private:double re;double im;};constexpr complex COMP(0.0,1.0);// creates a literal complexdouble x =1.0;constexpr complex cx1(x,0);// error: x is not a constant expressionconst complex cx2(x,1);// OK: runtime initializationconstexprdouble xx = COMP.real();// OK: compile-time initializationconstexprdouble imaglval = COMP.imag();// OK: compile-time initialization
complex cx3(2,4.6);// OK: runtime initialization
Tipps aus dem Buch Effective Modern C ++ von Scott Meyers über constexpr:
constexpr Objekte sind const und werden mit Werten initialisiert, die während der Kompilierung bekannt sind.
constexpr Funktionen erzeugen Ergebnisse zur Kompilierungszeit, wenn sie mit Argumenten aufgerufen werden, deren Werte während der Kompilierung bekannt sind.
constexprObjekte und Funktionen können in einem größeren Bereich von Kontexten verwendet werden als Nichtobjekte constexprund Funktionen.
constexpr ist Teil der Schnittstelle eines Objekts oder einer Funktion.
Vielen Dank für den großartigen Beispielcode, der die verschiedenen Situationen zeigt. So großartig einige der anderen Erklärungen auch sind, ich fand es viel nützlicher und verständlicher, den Code in Aktion zu sehen. Es hat mir wirklich geholfen, mein Verständnis für das, was vor sich geht, zu festigen.
RTHarston
35
Laut dem Buch "The C ++ Programming Language 4th Editon" von Bjarne Stroustrup
• const : bedeutet ungefähr "Ich verspreche, diesen Wert nicht zu ändern" (§7.5). Dies wird hauptsächlich verwendet, um Schnittstellen anzugeben, damit Daten an Funktionen übergeben werden können, ohne befürchten zu müssen, dass sie geändert werden.
Der Compiler erzwingt das Versprechen von const.
• constexpr : bedeutet ungefähr '' zur Kompilierungszeit auszuwerten '' (§10.4). Dies wird hauptsächlich verwendet, um Konstanten anzugeben, um
beispielsweise Folgendes zu ermöglichen :
constint dmv =17;// dmv is a named constantint var =17;// var is not a constantconstexprdouble max1 =1.4*square(dmv);// OK if square(17) is a constant expressionconstexprdouble max2 =1.4∗square(var);// error : var is not a constant expressionconstdouble max3 =1.4∗square(var);//OK, may be evaluated at run timedouble sum(constvector<double>&);// sum will not modify its argument (§2.2.5)vector<double> v {1.2,3.4,4.5};// v is not a constantconstdouble s1 = sum(v);// OK: evaluated at run timeconstexprdouble s2 = sum(v);// error : sum(v) not constant expression
Damit eine Funktion in einem konstanten Ausdruck verwendet werden kann, dh in einem Ausdruck, der vom Compiler ausgewertet wird, muss sie constexpr definiert werden . Zum Beispiel:
constexprdouble square(double x){return x∗x;}
Um constexpr zu sein, muss eine Funktion ziemlich einfach sein: nur eine return-Anweisung, die einen Wert berechnet. Eine constexpr-Funktion kann für nicht konstante Argumente verwendet werden. In diesem Fall ist das Ergebnis jedoch kein konstanter Ausdruck. Wir erlauben den Aufruf einer constexpr-Funktion mit Argumenten für nicht konstante Ausdrücke in Kontexten, die keine konstanten Ausdrücke erfordern, so dass wir nicht im Wesentlichen dieselbe Funktion zweimal definieren müssen: einmal für konstante Ausdrücke und einmal für Variablen.
An einigen Stellen sind konstante Ausdrücke für Sprachregeln (z. B. Array-Grenzen (§2.2.5, §7.3), Fallbezeichnungen (§2.2.4, §9.4.2), einige Vorlagenargumente (§25.2) und erforderlich Konstanten, die mit constexpr deklariert wurden). In anderen Fällen ist die Auswertung zur Kompilierungszeit wichtig für die Leistung. Unabhängig von Leistungsproblemen ist der Begriff der Unveränderlichkeit (eines Objekts mit unveränderlichem Zustand) ein wichtiges Designanliegen (§ 10.4).
Es gibt immer noch Leistungsprobleme. Scheint, dass die constexpr-Funktion, wenn sie zur Laufzeit ausgewertet wird, langsamer sein kann als die Nicht-constexpr-Version der Funktion. Auch wenn wir einen konstanten Wert haben, sollten wir "const" oder "constexpr" bevorzugen? (mehr eine Stil Frage generiert Assembly sieht gleich aus)
CoffeDeveloper
31
Beides constund constexprkann auf Variablen und Funktionen angewendet werden. Obwohl sie einander ähnlich sind, handelt es sich tatsächlich um sehr unterschiedliche Konzepte.
Beides constund constexprbedeuten, dass ihre Werte nach ihrer Initialisierung nicht mehr geändert werden können. Also zum Beispiel:
constint x1=10;constexprint x2=10;
x1=20;// ERROR. Variable 'x1' can't be changed.
x2=20;// ERROR. Variable 'x2' can't be changed.
Der Hauptunterschied zwischen constund constexprist der Zeitpunkt, zu dem ihre Initialisierungswerte bekannt sind (ausgewertet werden). Während die Werte von constVariablen sowohl zur Kompilierungszeit als auch zur Laufzeit constexprausgewertet werden können, werden sie immer zur Kompilierungszeit ausgewertet. Zum Beispiel:
int temp=rand();// temp is generated by the the random generator at runtime.constint x1=10;// OK - known at compile time.constint x2=temp;// OK - known only at runtime.constexprint x3=10;// OK - known at compile time.constexprint x4=temp;// ERROR. Compiler can't figure out the value of 'temp' variable at compile time so `constexpr` can't be applied here.
Der Hauptvorteil zu wissen, ob der Wert zur Kompilierungszeit oder zur Laufzeit bekannt ist, ist die Tatsache, dass Kompilierungszeitkonstanten immer dann verwendet werden können, wenn Kompilierungszeitkonstanten benötigt werden. In C ++ können Sie beispielsweise keine C-Arrays mit variablen Längen angeben.
int temp=rand();// temp is generated by the the random generator at runtime.int array1[10];// OK.int array2[temp];// ERROR.
Das heißt also:
constint size1=10;// OK - value known at compile time.constint size2=temp;// OK - value known only at runtime.constexprint size3=10;// OK - value known at compile time.int array3[size1];// OK - size is known at compile time.int array4[size2];// ERROR - size is known only at runtime time.int array5[size3];// OK - size is known at compile time.
So constVariablen beide definieren kann Kompilierung Konstanten wie size1verwendet werden können , dass Feldgrößen und zu spezifizieren Laufzeitkonstanten wie size2nur zur Laufzeit, die bekannt ist und nicht verwendet werden können , Feldgrößen zu definieren. constexprDefinieren Sie andererseits immer Kompilierungszeitkonstanten, die Arraygrößen angeben können.
Beides constund constexprkann auch auf Funktionen angewendet werden. Eine constFunktion muss eine Elementfunktion (Methode, Operator) sein, bei der die Anwendung eines constSchlüsselworts bedeutet, dass die Methode die Werte ihrer Elementfelder (nicht statisch) nicht ändern kann. Zum Beispiel.
class test
{int x;void function1(){
x=100;// OK.}void function2()const{
x=100;// ERROR. The const methods can't change the values of object fields.}};
A constexprist ein anderes Konzept. Es markiert eine Funktion (Mitglied oder Nichtmitglied) als die Funktion, die zur Kompilierungszeit ausgewertet werden kann, wenn Konstanten zur Kompilierungszeit als Argumente übergeben werden . Zum Beispiel können Sie dies schreiben.
constexprint func_constexpr(int X,int Y){return(X*Y);}int func(int X,int Y){return(X*Y);}int array1[func_constexpr(10,20)];// OK - func_constexpr() can be evaluated at compile time.int array2[func(10,20)];// ERROR - func() is not a constexpr function.int array3[func_constexpr(10,rand())];// ERROR - even though func_constexpr() is the 'constexpr' function, the expression 'constexpr(10,rand())' can't be evaluated at compile time.
Übrigens sind die constexprFunktionen die regulären C ++ - Funktionen, die aufgerufen werden können, auch wenn nicht konstante Argumente übergeben werden. In diesem Fall erhalten Sie jedoch die Nicht-Constexpr-Werte.
int value1=func_constexpr(10,rand());// OK. value1 is non-constexpr value that is evaluated in runtime.constexprint value2=func_constexpr(10,rand());// ERROR. value2 is constexpr and the expression func_constexpr(10,rand()) can't be evaluated at compile time.
Das constexprkann auch auf die Elementfunktionen (Methoden), Operatoren und sogar Konstruktoren angewendet werden. Zum Beispiel.
class test2
{staticconstexprint function(int value){return(value+1);}void f(){int x[function(10)];}};
Eine "verrücktere" Probe.
class test3
{public:int value;// constexpr const method - can't chanage the values of object fields and can be evaluated at compile time.constexprint getvalue()const{return(value);}constexpr test3(intValue): value(Value){}};constexpr test3 x(100);// OK. Constructor is constexpr.intarray[x.getvalue()];// OK. x.getvalue() is constexpr and can be evaluated at compile time.
Auch in C constexpr intexistiert, aber es ist geschriebenconst int
neugieriger Kerl
8
Wie bereits in @ 0x499602d2 erwähnt, wird constnur sichergestellt, dass ein Wert nach der Initialisierung nicht geändert werden kann, wenn as constexpr(eingeführt in C ++ 11) garantiert, dass die Variable eine Kompilierungszeitkonstante ist.
Betrachten Sie das folgende Beispiel (von LearnCpp.com):
cout <<"Enter your age: ";int age;
cin >> age;constint myAge{age};// worksconstexprint someAge{age};// error: age can only be resolved at runtime
A const int varkann zur Laufzeit dynamisch auf einen Wert gesetzt werden, und sobald es auf diesen Wert gesetzt ist, kann es nicht mehr geändert werden.
A constexpr int varkann nicht zur Laufzeit dynamisch festgelegt werden, sondern zur Kompilierungszeit. Sobald dieser Wert eingestellt ist, kann er nicht mehr geändert werden.
Hier ist ein gutes Beispiel:
int main(int argc,char*argv[]){constint p = argc;// p = 69; // cannot change p because it is a const// constexpr int q = argc; // cannot be, bcoz argc cannot be computed at compile time constexprint r =2^3;// this works!// r = 42; // same as const too, it cannot be changed}
Das obige Snippet lässt sich gut kompilieren und ich habe diejenigen auskommentiert, die einen Fehler verursachen.
Die Schlüsselbegriffe, die hier zur Kenntnis genommen werden müssen, sind die Begriffe von compile timeund run time. In C ++ wurden neue Innovationen eingeführt, mit denen ** know **bestimmte Dinge zur Kompilierungszeit so weit wie möglich verbessert werden sollen, um die Leistung zur Laufzeit zu verbessern.
Ich glaube nicht, dass eine der Antworten wirklich klar macht, welche Nebenwirkungen es hat oder was es tatsächlich ist.
constexprund constim Namespace / Dateibereich sind identisch, wenn sie mit einem Literal oder Ausdruck initialisiert werden; Aber mit einer Funktion, constdie von jeder Funktion initialisiert werden kann, aber constexprvon einem Nicht-Constexpr (einer Funktion, die nicht mit Constexpr oder einem Nicht-Constexpr-Ausdruck markiert ist) initialisiert wird, wird ein Compilerfehler generiert. Beide constexprund constsind implizit interne Verknüpfungen für Variablen (tatsächlich überleben sie nicht, um die Verknüpfungsstufe zu erreichen, wenn sie -O1 und stärker kompilieren, und staticzwingen den Compiler nicht, ein internes (lokales) Linkersymbol für constoder constexprbei at auszugeben -O1 oder stärker, das einzige Mal , es dies tut , ist , wenn Sie die Adresse der variablen nehmen. constund constexprwird ein internes Symbol sein , es sei denn mit ausgedrückt externdhextern constexpr/const int i = 3;muss verwendet werden). Bei einer Funktion erreicht constexprdie Funktion dauerhaft nie die Verknüpfungsstufe (unabhängig von externoder inlinein der Definition oder -O0 oder -Ofast), wohingegen dies constniemals der Fall ist staticund inlinenur diese Auswirkung auf -O1 und höher hat. Wenn eine const/ constexpr-Variable von einer constexprFunktion initialisiert wird , wird die Last immer mit einem Optimierungsflag optimiert, aber niemals, wenn die Funktion nur staticoder inlineist oder wenn die Variable kein const/ ist constexpr.
Standardzusammenstellung (-O0)
#include<iostream>constexprint multiply (int x,int y){return x * y;}externconstint val = multiply(10,10);int main (){
std::cout << val;}
kompiliert zu
val:.long100//extra external definition supplied due to extern
main:
push rbp
mov rbp, rsp
mov esi,100//substituted in as an immediate
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char>>::operator<<(int)
mov eax,0
pop rbp
ret
__static_initialization_and_destruction_0(int,int):...
jedoch
#include<iostream>constint multiply (int x,int y){return x * y;}constint val = multiply(10,10);//constexpr is an errorint main (){
std::cout << val;}
Kompiliert zu
multiply(int,int):
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], edi
mov DWORD PTR [rbp-8], esi
mov eax, DWORD PTR [rbp-4]
imul eax, DWORD PTR [rbp-8]
pop rbp
ret
main:
push rbp
mov rbp, rsp
mov eax, DWORD PTR val[rip]
mov esi, eax
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char>>::operator<<(int)
mov eax,0
pop rbp
ret
__static_initialization_and_destruction_0(int,int):...
mov esi,10
mov edi,10
call multiply(int,int)
mov DWORD PTR val[rip], eax
Dies zeigt deutlich, dass constexprdie Initialisierung der const/constexprDateibereichsvariablen zur Kompilierungszeit erfolgt und kein globales Symbol erzeugt, während bei Nichtverwendung die Initialisierung vor mainder Laufzeit erfolgt.
constexprFunktionen können constexprfür das gleiche Ergebnis auch aus anderen Funktionen heraus aufgerufen werden . constexpron a function verhindert auch die Verwendung von Elementen, die zur Kompilierungszeit in der Funktion nicht ausgeführt werden können. Zum Beispiel ein Anruf beim <<Bediener auf std::cout.
constexprat block scope verhält sich insofern gleich, als es einen Fehler erzeugt, wenn es von einer Nicht-Constexpr-Funktion initialisiert wird. Der Wert wird ebenfalls sofort ersetzt.
Letztendlich ist sein Hauptzweck wie die Inline-Funktion von C, aber sie ist nur dann wirksam, wenn die Funktion zum Initialisieren von Variablen für den Dateibereich verwendet wird (welche Funktionen in C nicht möglich sind, in C ++ jedoch, da sie die dynamische Initialisierung von Datei- ermöglichen). Bereichsvariablen), außer dass die Funktion auch kein globales / lokales Symbol in den Linker exportieren kann, selbst wenn extern/staticSie dies inlineauf C verwenden könnten ; Zuweisungsfunktionen für Block-Scope-Variablen können einfach mithilfe einer -O1-Optimierung ohne constexprC und C ++ eingefügt werden .
Schöner Punkt auf dem Linker. Könnte es im Allgemeinen als sicherer angesehen werden, constexpr zu verwenden, da dies zu weniger Symbollecks führt?
Neil McGill
1
@NeilMcGill nicht wirklich, da Inline und Statik dazu führen, dass der Compiler kein lokales Symbol zum Multiplizieren ausgibt, wenn er mit -O1 oder höher kompiliert. Constexpr ist das einzige, das die Last für val optimiert, aber ansonsten ist es identisch damit, statische oder Inline-Werte vor die Funktion zu stellen. Ich habe noch etwas anderes vergessen. Constexpr ist das einzige Schlüsselwort, das kein Symbol für die Funktion auf -O0, statisch und inline do ausgibt
Lewis Kelsey
1
Zunächst einmal sind beide Qualifikationsmerkmale in c ++. Eine deklarierte Variable const muss initialisiert werden und kann in Zukunft nicht mehr geändert werden. Daher hat eine als const deklarierte Variable im Allgemeinen bereits vor dem Kompilieren einen Wert.
Aber für constexpr ist es ein bisschen anders.
Für constexpr können Sie einen Ausdruck angeben, der während der Kompilierung des Programms ausgewertet werden kann.
Offensichtlich kann die als constexper deklarierte Variable in Zukunft nicht mehr wie const geändert werden.
constexpr
erstellt eine Kompilierungszeitkonstante;const
bedeutet einfach, dass der Wert nicht geändert werden kann.boost/hana
Möglicherweise kann dieser Artikel aus der Bibliothek einigeconstexpr
Probleme aufzeigen, die Sie verwenden könnenconstexpr
und wo Sie nicht können: boost.org/doc/libs/1_69_0/libs/hana/doc/html/…constexpr
damals auch neu :)Antworten:
Grundlegende Bedeutung und Syntax
Beide Schlüsselwörter können sowohl bei der Deklaration von Objekten als auch bei Funktionen verwendet werden. Der grundlegende Unterschied bei der Anwendung auf Objekte ist folgender:
const
deklariert ein Objekt als konstant . Dies impliziert eine Garantie, dass sich der Wert dieses Objekts nach der Initialisierung nicht ändert und der Compiler diese Tatsache für Optimierungen nutzen kann. Es hilft auch zu verhindern, dass der Programmierer Code schreibt, der Objekte ändert, die nach der Initialisierung nicht geändert werden sollten.constexpr
deklariert ein Objekt als zur Verwendung in den vom Standard als konstant bezeichneten Ausdrücken geeignet . Beachten Sie jedoch, dass diesconstexpr
nicht der einzige Weg ist, dies zu tun.Bei der Anwendung auf Funktionen ist der grundlegende Unterschied folgender:
const
kann nur für nicht statische Elementfunktionen verwendet werden, nicht für Funktionen im Allgemeinen. Es gibt eine Garantie dafür, dass die Elementfunktion keines der nicht statischen Datenelemente ändert.constexpr
kann sowohl mit Member- als auch Nicht-Member-Funktionen sowie mit Konstruktoren verwendet werden. Es deklariert die Funktion für die Verwendung in konstanten Ausdrücken . Der Compiler akzeptiert es nur, wenn die Funktion bestimmte Kriterien erfüllt (7.1.5 / 3,4), vor allem (†) :return
Anweisung zulässig. Im Fall eines Konstruktors sind nur eine Initialisierungsliste, typedefs und statische Zusicherungen zulässig. (= default
und= delete
sind aber auch erlaubt.)asm
Deklaration, einegoto
Anweisung, eine Anweisung mit einer anderen Bezeichnung alscase
unddefault
, try-block, Definition einer Variablen vom nicht-wörtlichen Typ, Definition einer Variablen mit statischer oder Thread-Speicherdauer, Definition einer Variablen, für die keine Initialisierung durchgeführt wird.Konstante Ausdrücke
Wie oben erwähnt, werden
constexpr
sowohl Objekte als auch Funktionen als für die Verwendung in konstanten Ausdrücken geeignet deklariert. Ein konstanter Ausdruck ist mehr als nur konstant:Es kann an Orten verwendet werden, an denen eine Auswertung zur Kompilierungszeit erforderlich ist, z. B. bei Vorlagenparametern und Array-Größenangaben:
Aber beachten Sie:
Das Deklarieren von etwas
constexpr
garantiert nicht unbedingt, dass es beim Kompilieren ausgewertet wird. Es kann für solche verwendet werden, aber es kann auch an anderen Orten verwendet werden, die zur Laufzeit ausgewertet werden.Ein Objekt kann zur Verwendung in konstanten Ausdrücken geeignet sein, ohne deklariert zu werden
constexpr
. Beispiel:Dies ist möglich, weil
N
es konstant ist und zur Deklarationszeit mit einem Literal initialisiert wird und die Kriterien für einen konstanten Ausdruck erfüllt, auch wenn er nicht deklariert istconstexpr
.Also wann muss ich eigentlich verwenden
constexpr
?Ein Objekt wie
N
oben kann als konstanter Ausdruck verwendet werden, ohne deklariert zu werdenconstexpr
. Dies gilt für alle Objekte, die:const
[Dies liegt an §5.19 / 2: Ein konstanter Ausdruck darf keine Unterausdrücke enthalten, die "eine Änderung von lWert zu rWert" beinhalten, es sei denn, […] ein GlWert vom Integral- oder Aufzählungstyp […] "Dank an Richard Smith für die Korrektur von my frühere Behauptung, dass dies für alle wörtlichen Typen gilt.]
Damit eine Funktion für die Verwendung in konstanten Ausdrücken geeignet ist, muss sie explizit deklariert werden
constexpr
. es reicht nicht aus, nur die Kriterien für Konstantausdrucksfunktionen zu erfüllen. Beispiel:Wann kann / soll ich beide
const
undconstexpr
zusammen verwenden?A. In Objektdeklarationen. Dies ist niemals erforderlich, wenn beide Schlüsselwörter auf dasselbe zu deklarierende Objekt verweisen.
constexpr
impliziertconst
.ist das gleiche wie
Beachten Sie jedoch, dass es Situationen geben kann, in denen sich die Schlüsselwörter jeweils auf verschiedene Teile der Deklaration beziehen:
Hier
NP
wird als Adresskonstantenausdruck deklariert, dh als Zeiger, der selbst ein konstanter Ausdruck ist. (Dies ist möglich, wenn die Adresse durch Anwenden des Adressoperators auf einen statischen / globalen Konstantenausdruck generiert wird.) Hier sind beideconstexpr
undconst
erforderlich:constexpr
bezieht sich immer auf den deklarierten Ausdruck (hierNP
), währendconst
aufint
(er deklariert einen Zeiger-) to-const). Das Entfernen vonconst
würde den Ausdruck unzulässig machen (weil (a) ein Zeiger auf ein nicht konstantes Objekt kein konstanter Ausdruck sein kann und (b)&N
tatsächlich ein Zeiger auf eine Konstante ist).B. In Mitgliedsfunktionsdeklarationen. In C ++ 11
constexpr
bedeutet diesconst
, dass dies in C ++ 14 und C ++ 17 nicht der Fall ist. Eine unter C ++ 11 deklarierte Mitgliedsfunktion alsmuss deklariert werden als
unter C ++ 14, um weiterhin als
const
Funktion verwendbar zu sein .quelle
constexpr
Funktion für einen nicht konstanten Ausdruck aufrufen , z. B. eine gewöhnliche Variable, dies vollkommen legal ist und die Funktion wie jede andere Funktion verwendet wird. Es wird zur Kompilierungszeit nicht ausgewertet (da dies nicht möglich ist). Vielleicht denken Sie, dass dies offensichtlich ist - aber wenn ich feststelle, dass eine als deklarierte Funktionconstexpr
immer zur Kompilierungszeit ausgewertet wird, könnte sie falsch interpretiert werden.constexpr
Objekte gesprochen, nicht über Funktionen. Ich stelle mirconstexpr
Objekte gerne so vor, dass sie die Auswertung der Werte zur Kompilierungszeit erzwingen, undconstexpr
Funktionen, bei denen die Funktion je nach Bedarf zur Kompilierungs- oder Laufzeit ausgewertet werden kann.mutable
können auch durchconst
Mitgliederfunktionen geändert werden .const
gilt für Variablen und verhindert , dass diese in Ihrem Code geändert werden.constexpr
teilt dem Compiler mit, dass dieser Ausdruck zu einem Wert für die Kompilierungszeitkonstante führt , sodass er an Stellen wie Array-Längen, Zuweisen zuconst
Variablen usw. verwendet werden kann. Der von Oli angegebene Link enthält viele hervorragende Beispiele.Grundsätzlich handelt es sich um zwei verschiedene Konzepte, die zusammen verwendet werden können (und sollten).
quelle
Überblick
const
garantiert, dass ein Programm den Wert eines Objekts nicht ändert . Jedoch,const
garantiert nicht , welche Art der Initialisierung das Objekt erfährt.Erwägen:
Die Funktion gibt
max()
lediglich einen Literalwert zurück. Da der Initialisierer jedoch ein Funktionsaufruf ist,mx
wird er zur Laufzeit initialisiert. Daher können Sie es nicht als konstanten Ausdruck verwenden :constexpr
ist ein neues C ++ 11-Schlüsselwort, mit dem Sie keine Makros und fest codierten Literale erstellen müssen. Unter bestimmten Bedingungen wird auch garantiert, dass Objekte einer statischen Initialisierung unterzogen werden . Es steuert die Auswertungszeit eines Ausdrucks. Durch die Durchsetzung der Kompilierung Zeitauswertung seines Ausdrucks ,constexpr
können Sie wahre definieren konstante Ausdrücke , die für zeitkritische Anwendungen von entscheidender Bedeutung sind, Systemprogrammierung, Vorlagen und allgemein gesprochen, in jedem Code, der auf der Kompilierung Zeitkonstanten beruht.Funktionen mit konstantem Ausdruck
Eine Funktion mit konstantem Ausdruck ist eine deklarierte Funktion
constexpr
. Sein Body darf nicht virtuell sein und nur aus einer einzigen return-Anweisung bestehen, abgesehen von typedefs und statischen Asserts. Die Argumente und der Rückgabewert müssen Literaltypen haben. Es kann mit Argumenten ohne konstanten Ausdruck verwendet werden, aber wenn dies erledigt ist, ist das Ergebnis kein konstanter Ausdruck.Eine Funktion mit konstantem Ausdruck soll Makros und fest codierte Literale ersetzen, ohne die Leistung oder die Typensicherheit zu beeinträchtigen .
Objekte mit konstantem Ausdruck
Ein Objekt mit konstantem Ausdruck ist ein deklariertes Objekt
constexpr
. Es muss mit einem konstanten Ausdruck oder einem Wert initialisiert werden, der von einem Konstruktor mit konstantem Ausdruck mit Argumenten mit konstantem Ausdruck erstellt wurde.Ein Objekt mit konstantem Ausdruck verhält sich so, als ob es deklariert worden wäre
const
, außer dass es vor der Verwendung initialisiert werden muss und sein Initialisierer ein konstanter Ausdruck sein muss. Folglich kann ein Objekt mit konstantem Ausdruck immer als Teil eines anderen konstanten Ausdrucks verwendet werden.Konstruktoren mit konstanter Expression
Ein Konstruktor mit konstantem Ausdruck ist ein deklarierter Konstruktor
constexpr
. Es kann eine Mitgliederinitialisierungsliste haben, aber sein Text muss leer sein, abgesehen von typedefs und statischen Asserts. Seine Argumente müssen Literaltypen haben.Ein Konstruktor mit konstantem Ausdruck ermöglicht es dem Compiler, das Objekt zur Kompilierungszeit zu initialisieren, vorausgesetzt, die Argumente des Konstruktors sind alle konstante Ausdrücke.
Tipps aus dem Buch Effective Modern C ++ von Scott Meyers über
constexpr
:constexpr
Objekte sind const und werden mit Werten initialisiert, die während der Kompilierung bekannt sind.constexpr
Funktionen erzeugen Ergebnisse zur Kompilierungszeit, wenn sie mit Argumenten aufgerufen werden, deren Werte während der Kompilierung bekannt sind.constexpr
Objekte und Funktionen können in einem größeren Bereich von Kontexten verwendet werden als Nichtobjekteconstexpr
und Funktionen.constexpr
ist Teil der Schnittstelle eines Objekts oder einer Funktion.Quelle: Verwenden von constexpr zur Verbesserung von Sicherheit, Leistung und Kapselung in C ++ .
quelle
Laut dem Buch "The C ++ Programming Language 4th Editon" von Bjarne Stroustrup
• const : bedeutet ungefähr "Ich verspreche, diesen Wert nicht zu ändern" (§7.5). Dies wird hauptsächlich verwendet, um Schnittstellen anzugeben, damit Daten an Funktionen übergeben werden können, ohne befürchten zu müssen, dass sie geändert werden.
Der Compiler erzwingt das Versprechen von const.
• constexpr : bedeutet ungefähr '' zur Kompilierungszeit auszuwerten '' (§10.4). Dies wird hauptsächlich verwendet, um Konstanten anzugeben, um
beispielsweise Folgendes zu ermöglichen :
Damit eine Funktion in einem konstanten Ausdruck verwendet werden kann, dh in einem Ausdruck, der vom Compiler ausgewertet wird, muss sie constexpr definiert werden .
Zum Beispiel:
Um constexpr zu sein, muss eine Funktion ziemlich einfach sein: nur eine return-Anweisung, die einen Wert berechnet. Eine constexpr-Funktion kann für nicht konstante Argumente verwendet werden. In diesem Fall ist das Ergebnis jedoch kein konstanter Ausdruck. Wir erlauben den Aufruf einer constexpr-Funktion mit Argumenten für nicht konstante Ausdrücke in Kontexten, die keine konstanten Ausdrücke erfordern, so dass wir nicht im Wesentlichen dieselbe Funktion zweimal definieren müssen: einmal für konstante Ausdrücke und einmal für Variablen.
An einigen Stellen sind konstante Ausdrücke für Sprachregeln (z. B. Array-Grenzen (§2.2.5, §7.3), Fallbezeichnungen (§2.2.4, §9.4.2), einige Vorlagenargumente (§25.2) und erforderlich Konstanten, die mit constexpr deklariert wurden). In anderen Fällen ist die Auswertung zur Kompilierungszeit wichtig für die Leistung. Unabhängig von Leistungsproblemen ist der Begriff der Unveränderlichkeit (eines Objekts mit unveränderlichem Zustand) ein wichtiges Designanliegen (§ 10.4).
quelle
Beides
const
undconstexpr
kann auf Variablen und Funktionen angewendet werden. Obwohl sie einander ähnlich sind, handelt es sich tatsächlich um sehr unterschiedliche Konzepte.Beides
const
undconstexpr
bedeuten, dass ihre Werte nach ihrer Initialisierung nicht mehr geändert werden können. Also zum Beispiel:Der Hauptunterschied zwischen
const
undconstexpr
ist der Zeitpunkt, zu dem ihre Initialisierungswerte bekannt sind (ausgewertet werden). Während die Werte vonconst
Variablen sowohl zur Kompilierungszeit als auch zur Laufzeitconstexpr
ausgewertet werden können, werden sie immer zur Kompilierungszeit ausgewertet. Zum Beispiel:Der Hauptvorteil zu wissen, ob der Wert zur Kompilierungszeit oder zur Laufzeit bekannt ist, ist die Tatsache, dass Kompilierungszeitkonstanten immer dann verwendet werden können, wenn Kompilierungszeitkonstanten benötigt werden. In C ++ können Sie beispielsweise keine C-Arrays mit variablen Längen angeben.
Das heißt also:
So
const
Variablen beide definieren kann Kompilierung Konstanten wiesize1
verwendet werden können , dass Feldgrößen und zu spezifizieren Laufzeitkonstanten wiesize2
nur zur Laufzeit, die bekannt ist und nicht verwendet werden können , Feldgrößen zu definieren.constexpr
Definieren Sie andererseits immer Kompilierungszeitkonstanten, die Arraygrößen angeben können.Beides
const
undconstexpr
kann auch auf Funktionen angewendet werden. Eineconst
Funktion muss eine Elementfunktion (Methode, Operator) sein, bei der die Anwendung einesconst
Schlüsselworts bedeutet, dass die Methode die Werte ihrer Elementfelder (nicht statisch) nicht ändern kann. Zum Beispiel.A
constexpr
ist ein anderes Konzept. Es markiert eine Funktion (Mitglied oder Nichtmitglied) als die Funktion, die zur Kompilierungszeit ausgewertet werden kann, wenn Konstanten zur Kompilierungszeit als Argumente übergeben werden . Zum Beispiel können Sie dies schreiben.Übrigens sind die
constexpr
Funktionen die regulären C ++ - Funktionen, die aufgerufen werden können, auch wenn nicht konstante Argumente übergeben werden. In diesem Fall erhalten Sie jedoch die Nicht-Constexpr-Werte.Das
constexpr
kann auch auf die Elementfunktionen (Methoden), Operatoren und sogar Konstruktoren angewendet werden. Zum Beispiel.Eine "verrücktere" Probe.
quelle
constexpr int
existiert, aber es ist geschriebenconst int
Wie bereits in @ 0x499602d2 erwähnt, wird
const
nur sichergestellt, dass ein Wert nach der Initialisierung nicht geändert werden kann, wenn asconstexpr
(eingeführt in C ++ 11) garantiert, dass die Variable eine Kompilierungszeitkonstante ist.Betrachten Sie das folgende Beispiel (von LearnCpp.com):
quelle
A
const int var
kann zur Laufzeit dynamisch auf einen Wert gesetzt werden, und sobald es auf diesen Wert gesetzt ist, kann es nicht mehr geändert werden.A
constexpr int var
kann nicht zur Laufzeit dynamisch festgelegt werden, sondern zur Kompilierungszeit. Sobald dieser Wert eingestellt ist, kann er nicht mehr geändert werden.Hier ist ein gutes Beispiel:
Das obige Snippet lässt sich gut kompilieren und ich habe diejenigen auskommentiert, die einen Fehler verursachen.
Die Schlüsselbegriffe, die hier zur Kenntnis genommen werden müssen, sind die Begriffe von
compile time
undrun time
. In C ++ wurden neue Innovationen eingeführt, mit denen** know **
bestimmte Dinge zur Kompilierungszeit so weit wie möglich verbessert werden sollen, um die Leistung zur Laufzeit zu verbessern.quelle
Ich glaube nicht, dass eine der Antworten wirklich klar macht, welche Nebenwirkungen es hat oder was es tatsächlich ist.
constexpr
undconst
im Namespace / Dateibereich sind identisch, wenn sie mit einem Literal oder Ausdruck initialisiert werden; Aber mit einer Funktion,const
die von jeder Funktion initialisiert werden kann, aberconstexpr
von einem Nicht-Constexpr (einer Funktion, die nicht mit Constexpr oder einem Nicht-Constexpr-Ausdruck markiert ist) initialisiert wird, wird ein Compilerfehler generiert. Beideconstexpr
undconst
sind implizit interne Verknüpfungen für Variablen (tatsächlich überleben sie nicht, um die Verknüpfungsstufe zu erreichen, wenn sie -O1 und stärker kompilieren, undstatic
zwingen den Compiler nicht, ein internes (lokales) Linkersymbol fürconst
oderconstexpr
bei at auszugeben -O1 oder stärker, das einzige Mal , es dies tut , ist , wenn Sie die Adresse der variablen nehmen.const
undconstexpr
wird ein internes Symbol sein , es sei denn mit ausgedrücktextern
dhextern constexpr/const int i = 3;
muss verwendet werden). Bei einer Funktion erreichtconstexpr
die Funktion dauerhaft nie die Verknüpfungsstufe (unabhängig vonextern
oderinline
in der Definition oder -O0 oder -Ofast), wohingegen diesconst
niemals der Fall iststatic
undinline
nur diese Auswirkung auf -O1 und höher hat. Wenn eineconst
/constexpr
-Variable von einerconstexpr
Funktion initialisiert wird , wird die Last immer mit einem Optimierungsflag optimiert, aber niemals, wenn die Funktion nurstatic
oderinline
ist oder wenn die Variable keinconst
/ istconstexpr
.Standardzusammenstellung (-O0)
kompiliert zu
jedoch
Kompiliert zu
Dies zeigt deutlich, dass
constexpr
die Initialisierung derconst/constexpr
Dateibereichsvariablen zur Kompilierungszeit erfolgt und kein globales Symbol erzeugt, während bei Nichtverwendung die Initialisierung vormain
der Laufzeit erfolgt.Kompilieren mit -Ofast
Auch -Ofast optimiert die Last nicht! https://godbolt.org/z/r-mhif , also brauchen Sie
constexpr
constexpr
Funktionen könnenconstexpr
für das gleiche Ergebnis auch aus anderen Funktionen heraus aufgerufen werden .constexpr
on a function verhindert auch die Verwendung von Elementen, die zur Kompilierungszeit in der Funktion nicht ausgeführt werden können. Zum Beispiel ein Anruf beim<<
Bediener aufstd::cout
.constexpr
at block scope verhält sich insofern gleich, als es einen Fehler erzeugt, wenn es von einer Nicht-Constexpr-Funktion initialisiert wird. Der Wert wird ebenfalls sofort ersetzt.Letztendlich ist sein Hauptzweck wie die Inline-Funktion von C, aber sie ist nur dann wirksam, wenn die Funktion zum Initialisieren von Variablen für den Dateibereich verwendet wird (welche Funktionen in C nicht möglich sind, in C ++ jedoch, da sie die dynamische Initialisierung von Datei- ermöglichen). Bereichsvariablen), außer dass die Funktion auch kein globales / lokales Symbol in den Linker exportieren kann, selbst wenn
extern/static
Sie diesinline
auf C verwenden könnten ; Zuweisungsfunktionen für Block-Scope-Variablen können einfach mithilfe einer -O1-Optimierung ohneconstexpr
C und C ++ eingefügt werden .quelle
Zunächst einmal sind beide Qualifikationsmerkmale in c ++. Eine deklarierte Variable const muss initialisiert werden und kann in Zukunft nicht mehr geändert werden. Daher hat eine als const deklarierte Variable im Allgemeinen bereits vor dem Kompilieren einen Wert.
Aber für constexpr ist es ein bisschen anders.
Für constexpr können Sie einen Ausdruck angeben, der während der Kompilierung des Programms ausgewertet werden kann.
Offensichtlich kann die als constexper deklarierte Variable in Zukunft nicht mehr wie const geändert werden.
quelle