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?
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ż, żeconstexpr
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, deklaracjagoto
, deklaracja z etykietą inną niżcase
idefault
, 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)
- ciało funkcji musi być nie wirtualne i niezwykle proste: oprócz typedefs i STATIC asserts, dozwolone jest tylko jedno polecenie
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 zadeklarowaneconstexpr
.
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 deklarowaneconstexpr
. 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
.
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.
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żeconst
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++.
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).
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.
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.
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
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++.
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.
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