Różnica między "constexpr" a " const`

Jaka jest różnica między constexpr a const?

  • Kiedy Mogę używać tylko jednego z nich?
  • Kiedy Mogę używać obu i jak wybrać jeden?
Author: jogojapan, 2013-01-02

9 answers

Podstawowe znaczenie i składnia

Oba słowa kluczowe mogą być używane zarówno w deklaracji obiektów, jak i funkcji. Podstawowa różnica przy zastosowaniu do obiektów jest następująca:

  • const deklaruje obiekt jako stała . Oznacza to gwarancję, że po zainicjowaniu wartość tego obiektu nie ulegnie zmianie, a kompilator może wykorzystać ten fakt do optymalizacji. Pomaga również uniemożliwić programiście pisanie kodu modyfikującego obiekty, które nie miały być modyfikowane po inicjalizacji.

  • constexpr deklaruje obiekt jako nadający się do użycia w tym, co standardowe wywołanie stałych wyrażeń. Ale zauważ, że constexpr nie jest jedynym sposobem, aby to zrobić.

Przy zastosowaniu do funkcji podstawowa różnica jest taka:

  • const może być używany tylko dla niestatycznych funkcji prętowych, a nie funkcji w ogóle. Daje gwarancję, że funkcja członka nie modyfikuje żadnych nie - statycznych członków danych (z wyjątkiem zmiennych członków danych, które mogą być modyfikowane w każdym razie).

  • constexpr może być używany zarówno z funkcjami prętowymi, jak i nie-prętowymi, a także z konstruktorami. Deklaruje funkcję nadającą się do użycia w wyrażeniach stałych . Kompilator zaakceptuje ją tylko wtedy, gdy funkcja spełnia określone kryteria (7.1.5/3,4), co najważniejsze(†):

    • ciało funkcji musi być nie wirtualne i niezwykle proste: oprócz typedefs i STATIC asserts, dozwolone jest tylko jedno polecenie return. W przypadku konstruktora dozwolone są tylko lista inicjalizacyjna, typedefs i STATIC assert. (= default i = delete są również dozwolone.)
    • od C++14 reguły są bardziej zrelaksowane, co jest dozwolone od tego czasu wewnątrz funkcji constexpr: asm deklaracja, deklaracja goto, deklaracja z etykietą inną niż case i default, try-block, definicja zmiennej typu nie dosłownego, definicja zmiennej typu zmienna statyczna lub czas przechowywania wątku, definicja zmiennej, dla której nie jest wykonywana inicjalizacja.
    • argumenty i typ zwracany muszą być typami literalnymi (tj. ogólnie rzecz biorąc, typy bardzo proste, zazwyczaj Skalary lub Agregaty)

Wyrażenia stałe

Jak wspomniano powyżej, constexpr deklaruje zarówno obiekty, jak i funkcje jako nadające się do użycia w wyrażeniach stałych. Wyrażenie stałe jest czymś więcej niż tylko stała:

  • Może być używany w miejscach wymagających oceny w czasie kompilacji, na przykład w parametrach szablonu i specyfikacjach wielkości tablicy:]}
      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
    
  • Ale uwaga:

  • Zadeklarowanie czegoś jako constexpr niekoniecznie gwarantuje, że zostanie ono ocenione podczas kompilacji. Może być używany do tego celu, ale może być również używany w innych miejscach, które są oceniane w czasie wykonywania.

  • Obiektmoże być nadaje się do stosowania w wyrażeniach stałych BEZ deklarowania constexpr. Przykład:

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

    Jest to możliwe, ponieważ N, będąc stałą i zainicjalizowaną w czasie deklaracji literałem, spełnia kryteria dla wyrażenia stałego, nawet jeśli nie jest zadeklarowane constexpr.

Więc kiedy muszę używać constexpr?

  • obiekt podobny do N powyżej może być użyty jako wyrażenie stałe BEZ bycia deklarowane constexpr. Jest to prawdą dla wszystkich obiektów, które są:
  • const
  • typu całkowego lub wyliczeniowego i
  • zainicjalizowana w czasie deklaracji wyrażeniem, które samo w sobie jest wyrażeniem stałym

[wynika to z §5.19/2: wyrażenie stałe nie może zawierać podwyrażenia, które obejmuje "modyfikację lvalue-to-rvalue, chyba że [ ... ] a glvalue typu integral lub enumeration [ ... ]" dzięki Richardowi Smithowi za sprostowanie mojego wcześniejszego twierdzenia, że było to prawdą dla wszystkich typów dosłownych.]

  • Aby funkcja nadawała się do użycia w wyrażeniach stałych, to musi być jawnie zadeklarowana constexpr; nie wystarczy, aby spełniała jedynie kryteria funkcji wyrażeń stałych. Przykład:

     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
     }
    

Kiedy mogę / powinienem używać obu, const i constexpr razem?

A. w obiekcie deklaracje.{[126] } nie jest to konieczne, gdy oba słowa kluczowe odnoszą się do tego samego obiektu, który ma być zadeklarowany. constexpr implikuje const.

constexpr const int N = 5;

Jest tym samym co

constexpr int N = 5;
Należy jednak pamiętać, że mogą wystąpić sytuacje, w których słowa kluczowe odnoszą się do różnych części deklaracji:]}
static constexpr int N = 3;

int main()
{
  constexpr const int *NP = &N;
}

Tutaj, NP jest zadeklarowana jako stałe wyrażenie adresu, tzn. wskaźnik, który sam jest stałym wyrażeniem. (Jest to możliwe, gdy adres jest generowany przez zastosowanie adresu operator do statycznego / globalnego wyrażenia stałej.) Tutaj zarówno constexpr jak i const są wymagane: constexpr zawsze odnosi się do zadeklarowanego wyrażenia (tutaj NP), podczas gdy const odnosi się do int (deklaruje wskaźnik-do-const). Usunięcie const uczyniłoby wyrażenie nielegalnym (ponieważ (a) wskaźnik do obiektu non-const nie może być wyrażeniem stałym, a (b) &N jest w rzeczywistości wskaźnikiem do stałej).

B. w deklaracjach funkcji członka. W C++11, constexpr implikuje const, natomiast w C++14 i C++17 tak nie jest. Funkcja member zadeklarowana w C++11 jako

constexpr void f();

Musi być zadeklarowana jako

constexpr void f() const;

W C++14, aby nadal być użytecznym jako funkcja const.

 647
Author: jogojapan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-05 06:49:29

const stosuje się do zmiennych i zapobiega ich modyfikacji w Twoim kodzie.

constexpr mówi kompilatorowi, że to wyrażenie daje wartość stałej czasowej kompilacji, więc może być używane w miejscach takich jak długości tablic, przypisywanie zmiennych const, itd. Link podany przez Oli ma wiele doskonałych przykładów.

Zasadniczo są to 2 różne pojęcia i mogą (i powinny) być używane razem.

 131
Author: Karthik T,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:22

Przegląd

  • const gwarantuje, że program nie zmienia wartości obiektu . Jednakże const nie gwarantuje, jakiego typu inicjalizacji obiekt jest poddawany.

    Rozważmy:

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

    Funkcja max() zwraca jedynie literalną wartość. Jednakże, ponieważ inicjalizacja jest wywołaniem funkcji, mx jest inicjalizowana w trybie runtime. Dlatego nie można jej używać jako stałej wyrażenie :

    int arr[mx];  // error: “constant expression required”
    
  • constexpr to nowe słowo kluczowe C++11, które pozbawia cię konieczności tworzenia makr i literałów na twardo. Gwarantuje również, pod pewnymi warunkami, że obiekty przechodzą statyczną inicjalizację . Kontroluje czas oceny wyrażenia. Przez wymuszenie kompilacyjnej oceny jego wyrażenia, constexpr pozwala zdefiniować prawdziwe wyrażenia stałe , które są kluczowe dla aplikacji o krytycznym czasie, programowania systemu, szablony, i ogólnie rzecz biorąc, w każdym kodzie, który opiera się na stałych w czasie kompilacji.

Stałe-funkcje ekspresji

A funkcja wyrażenia stałego jest funkcją zadeklarowaną constexpr. Jego ciało musi być nie wirtualne i składać się tylko z pojedynczej instrukcji return, poza typedefs i twierdzeniami statycznymi. Jej argumenty i zwracana wartość muszą mieć typy dosłowne. Może być używany z argumentami nie-stałymi wyrażeniami, ale gdy to nastąpi, wynik nie jest stała ekspresja.

Funkcja wyrażania stałej ma zastąpić makra i zakodowane literały bez utraty wydajności lub bezpieczeństwa typu.

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)

Obiekty stałej ekspresji

A obiekt wyrażeń stałych jest obiektem zadeklarowanym constexpr. Musi być zainicjalizowane wyrażeniem stałym lub wartością r zbudowaną przez konstruktor wyrażeń stałych z argumentami wyrażeń stałych.

A obiekt constant-expression zachowuje się tak, jakby został zadeklarowany const, z tą różnicą, że wymaga inicjalizacji przed użyciem, a jego inicjalizator musi być wyrażeniem stałym. W związku z tym obiekt wyrażenia stałego może być zawsze używany jako część innego wyrażenia stałego.

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

Konstruktory wyrażeń stałych

A konstruktor wyrażeń stałych jest konstruktorem zadeklarowanym constexpr. Może mieć listę inicjalizacyjną członka, ale jej ciało musi być puste, oprócz typedefs i STATIC asserts. Jego argumenty muszą mieć typy dosłowne.

Konstruktor wyrażeń stałych pozwala kompilatorowi zainicjalizować obiekt w czasie kompilacji, pod warunkiem, że argumenty konstruktora są wyrażeniami stałymi.

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

Wskazówki z książki efektywny Nowoczesny C++ Scott Meyers o constexpr:

  • constexpr obiekty są const i są inicjalizowane wartościami znanymi podczas kompilacji;
  • constexpr Funkcje wytwarzają compile-time-wyniki wywołane z argumentami, których wartości są znane podczas kompilacji;
  • Obiekty i funkcje mogą być używane w szerszym zakresie kontekstów niż Nie-constexpr obiekty i funkcje;
  • constexpr jest częścią interfejsu obiektu lub funkcji.

Źródło: [[90]}używanie constexpr do poprawy bezpieczeństwa, wydajności i enkapsulacji w C++.

 74
Author: zangw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-11 11:24:53

Według książki" The C++ Programming Language 4th Editon " Bjarne Stroustrup
const: co oznacza mniej więcej " obiecuję nie zmieniać tej wartości "(§7.5). Stosuje się go przede wszystkim aby określić interfejsy, tak aby dane mogły być przekazywane do funkcji bez obawy o ich modyfikację.
Kompilator wymusza obietnicę złożoną przez const.
* constexpr : co oznacza mniej więcej "do oceny w czasie kompilacji" (§10.4). Służy przede wszystkim do określania stałych, aby umożliwić
Na przykład:

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

Aby funkcja była użyteczna w wyrażeniu ciągłym, to znaczy w wyrażeniu, które będzie oceniane przez kompilator musi być zdefiniowany constexpr .
na przykład:

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


Aby być constexpr, funkcja musi być dość prosta: tylko Return-Instrukcja obliczająca wartość. A funkcja constexpr może być użyta dla nie-stałych argumentów, ale gdy to nastąpi, wynik nie jest stała ekspresja. Pozwalamy funkcji constexpr na be called with non-constant-expression arguments w kontekstach, które nie wymagają wyrażeń stałych, dzięki czemu nie musimy definiować zasadniczo ta sama funkcja dwa razy: raz dla wyrażeń stałych i raz dla zmiennych.
W kilku miejscach wyrażenia stałe są wymagane przez reguły językowe (np., §7.3), etykiety przypadków (§2.2.4, §9.4.2), niektóre argumenty szablonu (§25.2) oraz stałe deklarowane za pomocą constexpr). W innych przypadkach ocena w czasie kompilacji jest ważna dla wydajność. Niezależnie od zagadnienia performance, pojęcie niezmienności (przedmiotu o stanie niezmiennym) jest ważna kwestia projektowania (§10.4).

 42
Author: Mustafa Ekici,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-02 13:29:56

Zarówno const jak i constexpr mogą być stosowane do zmiennych i funkcji. Chociaż są one do siebie podobne, w rzeczywistości są bardzo różne koncepcje.

Zarówno const jak i constexpr oznaczają, że ich wartości nie można zmienić po ich zainicjowaniu. Tak na przykład:

const int x1=10;
constexpr int x2=10;

x1=20; // ERROR. Variable 'x1' can't be changed.
x2=20; // ERROR. Variable 'x2' can't be changed.

Zasadniczą różnicą pomiędzy const i constexpr jest czas, w którym ich wartości inicjalizacji są znane (oceniane). Podczas gdy wartości zmiennych const można oceniać zarówno w czasie kompilacji, jak i runtime, constexpr są zawsze oceniane podczas kompilacji. Na przykład:

int temp=rand(); // temp is generated by the the random generator at runtime.

const int x1=10; // OK - known at compile time.
const int x2=temp; // OK - known only at runtime.
constexpr int x3=10; // OK - known at compile time.
constexpr int x4=temp; // ERROR. Compiler can't figure out the value of 'temp' variable at compile time so `constexpr` can't be applied here.

Kluczową zaletą, aby wiedzieć, czy wartość jest znana w czasie kompilacji lub w czasie runtime, jest fakt, że stałe czasu kompilacji mogą być używane zawsze, gdy są potrzebne stałe czasu kompilacji. Na przykład, C++ nie pozwala na określenie C-tablic o zmiennej długości.

int temp=rand(); // temp is generated by the the random generator at runtime.

int array1[10]; // OK.
int array2[temp]; // ERROR.

Oznacza to, że:

const int size1=10; // OK - value known at compile time.
const int size2=temp; // OK - value known only at runtime.
constexpr int 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.

Więc const zmienne mogą definiować zarówno kompilować stałe czasowe Jak size1, które mogą być używane aby określić rozmiary tablic i stałe runtime , takie jak size2, które są znane tylko w czasie wykonywania i nie mogą być używane do definiowania rozmiarów tablic. Z drugiej strony constexpr zawsze definiuje stałe czasu kompilacji, które mogą określać rozmiary tablic.

Zarówno const jak i constexpr mogą być również stosowane do funkcji. Funkcja const musi być funkcją member (metoda, operator), gdzie zastosowanie słowa kluczowego const oznacza, że metoda nie może zmieniać wartości pól member (niestatycznych). Na przykład.

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 constexpr to inna koncepcja. Oznacza funkcję (member lub non-member) jako funkcję, która może być oceniana w czasie kompilacji , jeśli stałe czasu kompilacji są przekazywane jako ich argumenty . Na przykład możesz to napisać.

constexpr int 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.

Przy okazji constexpr funkcje są zwykłymi funkcjami C++, które mogą być wywoływane nawet jeśli przekazywane są niestałe argumenty. Ale w takim przypadku otrzymujesz wartości inne niż constexpr.

int value1=func_constexpr(10,rand()); // OK. value1 is non-constexpr value that is evaluated in runtime.
constexpr int value2=func_constexpr(10,rand()); // ERROR. value2 is constexpr and the expression func_constexpr(10,rand()) can't be evaluated at compile time.

constexpr może być również stosowane do funkcji prętowych( metod), operatorów, a nawet konstruktorów. Na przykład.

class test2
{
    static constexpr int function(int value)
    {
        return(value+1);
    }

    void f()
    {
        int x[function(10)];


    }
};

Bardziej "szalona" próbka.

class test3
{
    public:

    int value;

    // constexpr const method - can't chanage the values of object fields and can be evaluated at compile time.
    constexpr int getvalue() const
    {
        return(value);
    }

    constexpr test3(int Value)
        : value(Value)
    {
    }
};


constexpr test3 x(100); // OK. Constructor is constexpr.

int array[x.getvalue()]; // OK. x.getvalue() is constexpr and can be evaluated at compile time.
 39
Author: Timmy_A,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-25 02:29:00

A const int var można dynamicznie ustawić na wartość w trybie runtime i po ustawieniu na tę wartość nie można jej już zmieniać.

A constexpr int var nie może być ustawiany dynamicznie w czasie wykonywania, ale raczej w czasie kompilacji. Po ustawieniu tej wartości nie można jej już zmieniać.

Oto solidny przykład:

int main(int argc, char*argv[]) {
    const int 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 
    constexpr int r = 2^3; // this works!
    // r = 42; // same as const too, it cannot be changed
}

Powyższy fragment kompiluje się dobrze i skomentowałem te, które powodują błąd.

Kluczowymi pojęciami, na które należy zwrócić uwagę, są pojęcia compile time i run time. Nowe w C++ wprowadzono innowacje mające na celu jak najwięcej ** know ** pewnych rzeczy w czasie kompilacji w celu poprawy wydajności w czasie wykonywania.

Każda próba wyjaśnienia, która nie wiąże się z dwoma kluczowymi pojęciami powyżej, jest halucynacją.
 12
Author: eigenfield,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-24 07:58:59

Jak już wspomniano @0x499602d2, const zapewnia tylko, że wartość nie może zostać zmieniona po inicjalizacji, gdzie as constexpr (wprowadzony w C++11) gwarantuje, że zmienna jest stałą czasową kompilacji.
Rozważ następujący przykład(z 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
 8
Author: Lokesh Meher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-05 10:33:51

Myślę, że żadna z odpowiedzi nie wyjaśnia dokładnie, jakie ma skutki uboczne, lub rzeczywiście, co to jest.

constexpr i {[5] } w przestrzeni nazw / file-scope są identyczne, gdy są inicjalizowane literalnym lub wyrażeniem; ale w przypadku funkcji, {[5] } mogą być inicjowane przez dowolną funkcję, ale constexpr inicjowane przez inną niż constexpr (funkcja, która nie jest oznaczona wyrażeniem constexpr lub innym wyrażeniem constexpr) wygeneruje błąd kompilatora. Zarówno constexpr, jak i {[5] } są wewnętrznymi powiązaniami dla zmiennych (właściwie, nie przetrwają one, aby dostać się do etapu łączenia, jeśli kompilowanie-O1 i stronger, a static nie zmusza kompilatora do emitowania wewnętrznego (lokalnego) symbolu linkera dla const lub constexpr gdy at-o1 lub stronger; robi to tylko wtedy, gdy przyjmuje się adres zmiennej. const i constexpr będą symbolami wewnętrznymi, chyba że należy użyć symbolu extern, tj. extern constexpr/const int i = 3;). W funkcji constexpr sprawia, że funkcja trwale nigdy nie osiąga etapu łączenia (niezależnie od extern lub inline w definicji lub-O0 lub-Ofast), podczas gdy const nigdy tego nie robi, a static i inline mają tylko ten wpływ na-O1 i powyżej. Gdy a const/constexpr zmienna jest inicjalizowana przez funkcję constexpr, obciążenie jest zawsze optymalizowane za pomocą dowolnego znacznika optymalizacji, ale nigdy nie jest optymalizowane, jeśli funkcja jest tylko static lub inline, lub jeśli zmienna nie jest const/constexpr.

Standard compilation (- O0)

#include<iostream>
constexpr int multiply (int x, int y)
{

  return x * y;
}

extern const int val = multiply(10,10);
int main () {
  std::cout << val;
} 

Kompiluje do

val:
        .long   100  //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):
        . 
        . 
        . 

Jednakże

#include<iostream>
const int multiply (int x, int y)
{

  return x * y;
}

const int val = multiply(10,10); //constexpr is an error
int main () {
  std::cout << val;
}

Kompiluje do

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

To wyraźnie pokazuje, że constexpr powoduje inicjalizację zmiennej const/constexpr file-scope w czasie kompilacji i nie generuje żadnego symbolu globalnego, podczas gdy nieużywanie jej powoduje inicjalizację przed main w czasie wykonywania.

Kompilowanie przy użyciu-Ofast

Even-Ofast nie optymalizuje obciążenia! https://godbolt.org/z/r-mhif , więc ty potrzebujesz constexpr


constexpr funkcje mogą być również wywoływane z wewnątrz innych constexpr funkcji dla tego samego wyniku. constexpr w funkcji uniemożliwia również użycie czegokolwiek, czego nie można zrobić w czasie kompilacji funkcji; na przykład wywołanie operatora << na std::cout.

constexpr w bloku zakres zachowuje się tak samo, ponieważ generuje błąd, jeśli zainicjowany przez funkcję non-constexpr; wartość jest również podstawiana natychmiast.

W końcu, jego głównym celem jest jak C ' S funkcja inline, ale jest skuteczna tylko wtedy, gdy funkcja jest używana do inicjalizacji zmiennych z zakresu pliku (czego funkcje nie mogą zrobić w C, ale mogą w C++, ponieważ pozwala to na dynamiczną inicjalizację zmiennych z zakresu pliku), z wyjątkiem funkcji nie może eksportować globalnego / lokalnego symbolu do linkera, nawet za pomocą extern/static, co można zrobić z {[19] } W C; Funkcje przypisywania zmiennych z zakresu bloku mogą być inlinowane po prostu za pomocą optymalizacji-O1 bez constexpr W C i C++.

 3
Author: Lewis Kelsey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-03 12:15:46

Po pierwsze, oba są kwalifikatorami w c++. Zmienna zadeklarowana const musi być zainicjalizowana i nie może być zmieniona w przyszłości. Stąd ogólnie zmienna zadeklarowana jako const będzie miała wartość jeszcze przed kompilacją.

Ale dla constexpr jest trochę inaczej.

Dla constexpr, możesz podać wyrażenie, które może być oceniane podczas kompilacji programu.

Oczywiście zmienna zadeklarowana jako constexper nie może być zmieniona w przyszłości, tak jak const.

 1
Author: Subhash Malireddy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-13 12:59:59