Skirtumas tarp `constexpr` ir` const`

Koks skirtumas tarp constexpr ir const ?

  • Kada galiu naudoti tik vieną iš jų?
  • Kada aš galiu naudoti ir kaip pasirinkti vieną iš jų?
293
02 янв. MBZ yra nustatytas sausio 02 d 2013-01-02 04:42 '13 ne 4:42 2013-01-02 04:42
@ 5 atsakymai

Pagrindinė reikšmė ir sintaksė

Abu raktiniai žodžiai gali būti naudojami deklaruojant objektus, taip pat funkcijas. Pagrindinis skirtumas, kai taikomas objektams, yra toks:

  • const pareiškia, kad objektas yra nuolatinis. Tai reiškia, kad po inicijavimo šio objekto vertė nepasikeis, ir kompiliatorius gali naudoti šį faktą optimizavimui. Ji taip pat padeda užkirsti kelią programuotojui rašyti kodą, kuris pakeičia objektus, kurie nebuvo pakeisti po iniciacijos.

  • constexpr pareiškia, kad objektas yra tinkamas naudoti, nes standartas remiasi nuolatinėmis išraiškomis. Tačiau atkreipkite dėmesį, kad constexpr nėra vienintelis būdas tai padaryti.

Taikant funkcijas, pagrindinis skirtumas yra toks:

  • const gali būti naudojamas tik ne statinėms nario funkcijoms, o ne funkcijoms apskritai. Tai užtikrina, kad nario funkcija nekeičia jokių nestatinių duomenų elementų.

  • constexpr gali būti naudojamas tiek su nario, tiek ne nario funkcijomis, taip pat su konstruktoriais. Jis deklaruoja funkciją, tinkančią naudoti nuolatinėse išraiškose. Kompiliatorius jį priims tik tuo atveju, jei funkcija atitinka tam tikrus kriterijus (7.1.5 / 3.4), o svarbiausia ( dagger;) :

    • Funkcijų kūnas turi būti ne virtualus ir labai paprastas: be tipedefs ir statinių pareiškimų leidžiama naudoti tik vieną return ataskaitą. Konstruktoriaus atveju leidžiama tik inicijavimo sąrašo, tipedefų ir statinio patvirtinimo. ( = default = delete pat leidžiama = delete ir = delete ).
    • Argumentai ir grąžinimo tipas turi būti tiesioginiai (tai yra, paprastai kalbant, labai paprasti tipai, paprastai skalarai ar agregatai)

Nuolatinės išraiškos

Kaip minėta pirmiau, constexpr deklaruoja abu objektus, taip pat funkcijas, tinkamas naudoti nuolatinėse išraiškose. Nuolatinė išraiška yra daugiau nei tik konstanta:

  • Jis gali būti naudojamas vietose, kur reikalingas kompiliavimo laiko įvertinimas, pvz., Šablonų parametrai ir masyvo dydžio specifikatoriai:

     template<int N> class fixed_size_list {  }; fixed_size_list<X> mylist; // X must be an integer constant expression int numbers[X]; // X must be an integer constant expression 
  • Tačiau atkreipkite dėmesį:

    • constexpr kažką kaip constexpr nebūtinai garantuoja, kad jis bus įvertintas kompiliavimo metu. Jis gali būti naudojamas šiam tikslui, tačiau jis gali būti naudojamas kitose vietose, kurios taip pat vertinamos vykdymo metu.

    • Objektas gali būti tinkamas naudoti pastovios išraiškos būdu be constexpr . Pavyzdys:

       int main() { const int N = 3; int numbers[N] = {1, 2, 3}; // N is constant expression return 0; } 

    Tai įmanoma, nes N , pastovios ir inicijuotos per pažodinę deklaraciją, atitinka nuolatinės išraiškos kriterijus, net jei ji nėra deklaruota.

Taigi, kada man tikrai reikia naudoti constexpr ?

  • objektas , kaip N aukščiau N , galima naudoti kaip nuolatinę išraišką be constexpr . Tai pasakytina apie visus objektus, kurie:

    • const
    • integruoto tipo arba skaičiavimo tipo ir
    • deklaracija suformuluota išraiška, kuri savaime yra nuolatinė išraiška

    [Taip yra dėl §19.19 / 2: pastovios išraiškos neturėtų apimti subexpressions, apimančių „keičiant lvalue-rvalue reikšmę, išskyrus atvejus, kai [...] gl vertė yra sveikasis skaičius arba išvardytas [...] tipas“. mano ankstesnių pareiškimų, kad tai pasakytina apie visus literatūrus.]

  • Funkcijai, tinkančiai naudoti nuolatinėse išraiškose, ji turi <i> deklaruoti constexpr ; nepakanka, kad jis tiesiog atitiktų nuolatinės išraiškos funkcijų kriterijus. Pavyzdys:

     template<int N> class list { }; constexpr int sqr1(int arg) { return arg * arg; } int sqr2(int arg) { return arg * arg; } int main() { const int X = 2; list<sqr1(X)> mylist1; // OK: sqr1 is constexpr list<sqr2(X)> mylist2; // wrong: sqr2 is not constexpr return 0; } 

Kada turėčiau naudoti abu parametrus, const ir constexpr ?

a Objektų deklaracijose. Tai niekada nereikalinga, kai abu raktiniai žodžiai nurodo tą patį objektą, kuris turi būti paskelbtas. constexpr reiškia const .

 constexpr const int N = 5; 

atitinka

 constexpr int N = 5; 

Tačiau atkreipkite dėmesį, kad gali būti situacijų, kai raktiniai žodžiai nurodo skirtingas skelbimo dalis:

 static constexpr int N = 3; int main() { constexpr const int *NP =  return 0; } 

Čia NP deklaruojamas kaip adreso konstanta, ty rodyklė, kuri pati yra pastovi išraiška. (Tai įmanoma, kai adresas generuojamas taikant constexpr operatorių statinei / visuotinei pastoviai išraiškai.) Čia reikalingi ir constexpr ir const : constexpr visada nurodo deklaruojamą išraišką (čia NP ), ir const yra int (deklaruoja žymiklį į konstanta). Šalinant const bus išraiška neteisėta (nes (a) rodyklė į nestabilų objektą negali būti nuolatinė išraiška, ir (b) > iš tikrųjų yra rodyklė į konstanta.

B. Funkcijų narių deklaracijose. C ++ 11, constexpr reiškia const taip pat nario funkcijas. Tačiau tikėtina, kad tai pasikeis į C ++ 14. Pagal dabartinius projektus constexpr reikės tik objektams, o ne nario funkcijoms, dėl siūlomo pakeitimo 7.1.5 / 8. Todėl nario funkcija deklaruota C ++ 11 as

 constexpr void f(); 

turėtų būti deklaruojama kaip

 constexpr void f() const; 

pagal C ++ 14, vis dar bus naudojamas kaip const . Geriau pažymėti savo „ constexpr funkcijas kaip „ const , kad vėliau nereikėtų keisti daug kodo.


( dagger;) C ++ 14 greičiausiai bus sušvelnintos priimtinų constexpr funkcijų constexpr . Richard Smith pasiūlymas neseniai buvo priimtas C ++ 14 .

295
02 янв. atsakymas, kurį pateikė jogojapan 02 Jan 2013-01-02 08:10 '13, 8:10, 2013-01-02 08:10

const taikomas kintamiesiems ir neleidžia jiems keisti kodo.

constexpr pasakoja kompiliatoriui, kad ši išraiška gaunama kompiliavimo laiko reikšmė, todėl ji gali būti naudojama tokiose vietose, kaip masyvo ilgiai, priskiriant const kintamuosius ir tt Olio pateikta nuoroda turi daug puikių pavyzdžių.

Iš esmės jie paprastai yra dvi skirtingos sąvokos ir gali (ir turėtų) būti naudojamos kartu.

66
02 янв. Atsakymas duotas Karthik T 02 Jan. 2013-01-02 04:44 '13, 4:44, 2013-01-02 04:44

Peržiūra

  • const užtikrina, kad programa nekeičia objekto vertės . Tačiau „ const “ negarantuoja, kokio tipo inicijavimas atliekamas.

    Apsvarstykite:

     const int mx = numeric_limits<int>::max(); // OK: runtime initialization 

    max() funkcija tiesiog grąžina pažodinę vertę. Tačiau, kadangi iniciatorius yra funkcijų skambutis, mx inicijuojamas vykdymo metu. Todėl negalite naudoti kaip nuolatinės išraiškos:

     int arr[mx]; // error: "constant expression required" 
  • constexpr yra naujas C + + 11 raktinis žodis, kuris pašalina poreikį kurti makrokomandas ir sunkiai koduotus literatūrus. Ji taip pat tam tikromis sąlygomis užtikrina, kad objektai būtų statiškai inicijuoti. Jis kontroliuoja išraiškos vertinimo laiką. Vertindami savo išraiškos kompiliavimo laiką , constexpr leidžia jums apibrėžti tikras nuolatines išraiškas, kurios yra svarbios kritinėms programoms, sistemos programavimui, modeliams ir, apskritai, bet kokiam kodui, kuris priklauso nuo kompiliavimo laiko konstantų.

Nuolatinės raiškos funkcijos

constexpr ekspresijos funkcija yra deklaruota funkcija constexpr . Jo kūnas turi būti ne virtualus ir susideda tik iš vienos grąžinimo ataskaitos, išskyrus tipedefs ir statinius pareiškimus. Jo argumentai ir grąžinimo vertė turi turėti literatūrą. Jis gali būti naudojamas su ne pastovios išraiškos argumentais, bet kai tai daroma, rezultatas nėra nuolatinė išraiška.

Nuolatinės išraiškos funkcija skirta pakeisti makrokomandas ir sunkiai koduotus literatūros šaltinius neprarandant našumo ar tipo saugos.

 constexpr int max() { return INT_MAX; } // OK constexpr long long_max() { return 2147483647; } // OK constexpr bool get_val() { bool res = false; return res; } // error: body is not just a return statement constexpr int square(int x) { return x * x; } // OK: compile-time evaluation only if x is a constant expression const int res = square(5); // OK: compile-time evaluation of square(5) int y = getval(); int n = square(y); // OK: runtime evaluation of square(y) 

Objektai su pastovia išraiška

Nuolatinės išraiškos objektas yra deklaruotas objektas constexpr . Jis turi būti inicijuotas pastovia išraiška arba rvalue reikšme, sukurta pastovios išraiškos konstruktoriaus pastovios išraiškos argumentais.

Pastovios išraiškos objektas elgiasi taip, tarsi jis būtų paskelbtas const , išskyrus tai, kad jam reikia inicijuoti prieš naudojimą, ir jo iniciatorius turi būti nuolatinė išraiška. Todėl pastovios ekspresijos objektas visada gali būti naudojamas kaip kitos nuolatinės išraiškos dalis.

 struct S { constexpr int two(); // constant-expression function private: static constexpr int sz; // constant-expression object }; constexpr int S::sz = 256; enum DataPacket { Small = S::two(), // error: S::two() called before it was defined Big = 1024 }; constexpr int S::two() { return sz*2; } constexpr S s; int arr[s.two()]; // OK: s.two() called after its definition 

Pastovios ekspresijos konstruktoriai

Pastovios ekspresijos konstruktorius yra deklaruotas constexpr konstruktorius. Jis gali turėti narių iniciacijos sąrašą, tačiau jo kūnas turi būti tuščias, išskyrus tipedefs ir statinius teiginius. Jos argumentai turi būti tiesioginiai.

Pastovios ekspresijos konstruktorius leidžia kompiliatoriui inicijuoti objektą kompiliavimo metu, jei konstruktoriaus argumentai yra pastovios išraiškos.

 struct complex { // constant-expression constructor constexpr complex(double r, double i) : re(r), im(i) { } // OK: empty body // constant-expression functions constexpr double real() { return re; } constexpr double imag() { return im; } private: double re; double im; }; constexpr complex COMP(0.0, 1.0); // creates a literal complex double x = 1.0; constexpr complex cx1(x, 0); // error: x is not a constant expression const complex cx2(x, 1); // OK: runtime initialization constexpr double xx = COMP.real(); // OK: compile-time initialization constexpr double imaglval = COMP.imag(); // OK: compile-time initialization complex cx3(2, 4.6); // OK: runtime initialization 

Patarimai iš knygos „Efektyvus šiuolaikinis C + +“ Scott Meyers apie constexpr :

  • constexpr const objektai ir inicijuojami vertėmis, žinomomis kompiliavimo metu;
  • constexpr funkcijos sukuria kompiliavimo rezultatus pokalbio metu su argumentais, kurių vertės žinomos kompiliavimo metu;
  • constexpr objektai ir funkcijos gali būti naudojami platesniame kontekste nei ne constexpr objektai ir funkcijos;
  • constexpr yra objektų ar funkcijų sąsajos dalis.

Šaltinis: naudojant „constexpr“ siekiant pagerinti saugumą, našumą ir kapsuliavimą „C ++“ .

33
01 янв. atsakymas pateikiamas zangw 01 sausio. 2016-01-01 10:45 '16 at 10:45 2016-01-01 10:45

Pagal Bjarne Straustupo knygą „C ++ 4th Editon programavimo kalba“
const : netiesiogiai suprantama: „Pažadu nekeisti šios vertės (§7.5). Tai pirmiausia naudojama norint nurodyti sąsajas, kad duomenys būtų perduoti funkcijoms, nebijojant, kad jie bus pakeisti.
Kompiliatorius vykdo const.
• „ constexpr“ : apytikriai „“ vertė turi būti vertinama kompiliavimo metu (§10.4). Tai dažniausiai naudojama nustatyti konstantas, kurias reikia išspręsti.

 const int dmv = 17; // dmv is a named constant int var = 17; // var is not a constant constexpr double max1 = 1.4*square(dmv); // OK if square(17) is a constant expression constexpr double max2 = 1.4∗square(var); // error : var is not a constant expression const double max3 = 1.4∗square(var); //OK, may be evaluated at run time double sum(const vector<double> // sum will not modify its argument (§2.2.5) vector<double> v {1.2, 3.4, 4.5}; // v is not a constant const double s1 = sum(v); // OK: evaluated at run time constexpr double s2 = sum(v); // error : sum(v) not constant expression 

Funkcijai, kuri gali būti naudojama pastovioje išraiška, ty išraiškoje, kurią vertins kompiliatorius, ji turi būti apibrėžta constexpr .
Pavyzdžiui:

 constexpr double square(double x) { return x∗x; } 


Norint tapti constexpr, funkcija turi būti gana paprasta: tiesiog grąžinimo ataskaita, apskaičiuojanti vertę. Constexpr funkcija gali būti naudojama nenuolatiniams argumentams, bet kai tai daroma, rezultatas nėra nuolatinė išraiška. Konstekso funkciją leidžiame skambinti ne pastoviais išraiškos argumentais kontekstuose, kuriems nereikia nuolatinių išraiškų, todėl nereikia iš esmės apibrėžti tos pačios funkcijos dvigubai: vieną kartą pastoviems reiškiniams ir vieną kartą kintamiesiems.
Keliose vietose reikalingos pastovios išraiškos naudojant kalbos taisykles (pvz., Masyvo ribas (§2.5.5, §7.3), atvejo etiketes (2.2.4 punktas, 9.4.2 punktas), kai kuriuos šablono argumentus (§ 25.2) ir konstantas deklaruota naudojant konstexprą). Kitais atvejais kompiliavimo laiko įvertinimas yra svarbus vykdymui. Nepriklausomai nuo efektyvumo problemos, nekintamumo sąvoka (pastovios būklės objektas) yra svarbi projektavimo problema (§10.4).

18
02 окт. Atsakymas pateikiamas Mustafa Ekici 02 okt. 2013-10-02 15:58 '13, 15:58, 2013-10-02 15:58

Kaip jau minėta @ 0x499602d2, const garantuoja, kad po iniciacijos vertė negali būti pakeista, kai constexpr (įvedamas C ++ 11) garantuoja, kad kintamasis yra kompiliavimo laiko konstanta.
Apsvarstykite šį pavyzdį (iš LearnCpp.com):

 cout << "Enter your age: "; int age; cin >> age; const int myAge{age}; // works constexpr int someAge{age}; // error: age can only be resolved at runtime 
3
05 июня '16 в 13:33 2016-06-05 13:33 atsakymą pateikė Lokesh Meher birželio 15 d. 16 val. 13:33 2016-06-05 13:33

Kiti klausimai apie žymes arba Užduoti klausimą