Saya tidak berpikir salah satu jawaban benar-benar menjelaskan dengan tepat apa efek sampingnya, atau memang, apa itu.
constexpr
dan const
pada namespace / file-scope identik ketika diinisialisasi dengan literal atau ekspresi; tetapi dengan suatu fungsi, const
dapat diinisialisasi dengan fungsi apa pun, tetapi constexpr
diinisialisasi oleh non-constexpr (fungsi yang tidak ditandai dengan constexpr atau ekspresi non constexpr) akan menghasilkan kesalahan kompilator. Keduanya constexpr
dan const
merupakan keterkaitan internal implisit untuk variabel (yah sebenarnya, mereka tidak bertahan untuk sampai ke tahap menghubungkan jika kompilasi -O1 dan lebih kuat, dan static
tidak memaksa kompiler untuk memancarkan simbol penghubung internal (lokal) untuk const
atau constexpr
ketika pada -O1 atau lebih kuat, satu-satunya waktu melakukan ini adalah jika Anda mengambil alamat variabel, const
dan constexpr
akan menjadi simbol internal kecuali dinyatakan dengan extern
ieextern constexpr/const int i = 3;
perlu digunakan). Pada suatu fungsi, constexpr
membuat fungsi secara permanen tidak pernah mencapai tahap menghubungkan (terlepas dari extern
atau inline
dalam definisi atau -O0 atau -Ofast), sedangkan const
tidak pernah melakukannya, dan static
dan inline
hanya memiliki efek ini pada -O1 dan di atas. Ketika a const
/ constexpr
variabel diinisialisasi oleh suatu constexpr
fungsi, beban selalu dioptimalkan dengan flag optimasi apa pun, tetapi itu tidak pernah dioptimalkan jika fungsi hanya static
atau inline
, atau jika variabel bukan a const
/ constexpr
.
Kompilasi standar (-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;
}
kompilasi ke
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):
.
.
.
Namun
#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;
}
Kompilasi ke
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
Ini jelas menunjukkan bahwa constexpr
menyebabkan inisialisasi const/constexpr
variabel file-lingkup terjadi pada waktu kompilasi dan tidak menghasilkan simbol global, sedangkan tidak menggunakannya menyebabkan inisialisasi terjadi sebelum main
saat runtime.
Kompilasi menggunakan -Ofast
Bahkan -Ofast tidak mengoptimalkan beban! https://godbolt.org/z/r-mhif , jadi Anda perlu constexpr
constexpr
fungsi juga bisa dipanggil dari dalam lainnya constexpr
fungsi untuk hasil yang sama. constexpr
pada suatu fungsi juga mencegah penggunaan apa pun yang tidak dapat dilakukan pada waktu kompilasi dalam fungsi; misalnya, panggilan ke <<
operator aktif std::cout
.
constexpr
pada lingkup blok berperilaku sama karena menghasilkan kesalahan jika diinisialisasi oleh fungsi non-constexpr; nilainya juga diganti segera.
Pada akhirnya, tujuan utamanya adalah seperti fungsi inline C, tetapi hanya efektif ketika fungsi tersebut digunakan untuk menginisialisasi variabel lingkup file (yang fungsi tidak dapat dilakukan pada C, tetapi mereka dapat pada C ++ karena memungkinkan inisialisasi dinamis file- variabel lingkup), kecuali fungsi tidak dapat mengekspor simbol global / lokal ke linker juga, bahkan menggunakan extern/static
, yang Anda bisa dengan inline
di C; fungsi penugasan variabel blok-lingkup dapat diuraikan hanya dengan menggunakan optimasi -O1 tanpa constexpr
pada C dan C ++.
constexpr
menciptakan konstanta waktu kompilasi;const
hanya berarti bahwa nilai tidak dapat diubah.