Keduanya konstan waktu kompilasi. Tapi Anda bisa melakukan const_cast yang pertama dan menulisnya. Tapi itu akan dioptimalkan oleh kompiler karena ini tidak mempengaruhi "membaca" seperti yang terjadi pada waktu kompilasi.
Bonita Montero
Jawaban:
347
Saya percaya ada perbedaan. Mari kita ganti namanya sehingga kita bisa membicarakannya lebih mudah:
Kedua PI1dan PI2yang konstan, yang berarti Anda tidak bisa mengubah mereka. Namun hanyaPI2 konstanta waktu kompilasi. Ini akan diinisialisasi pada waktu kompilasi. PI1dapat diinisialisasi pada waktu kompilasi atau waktu berjalan. Selain itu, hanyaPI2 dapat digunakan dalam konteks yang memerlukan konstanta waktu kompilasi. Sebagai contoh:
Seperti yang harus Anda gunakan? Gunakan mana yang memenuhi kebutuhan Anda. Apakah Anda ingin memastikan bahwa Anda memiliki konstanta waktu kompilasi yang dapat digunakan dalam konteks di mana konstanta waktu kompilasi diperlukan? Apakah Anda ingin dapat menginisialisasi dengan perhitungan yang dilakukan saat run time? Dll
Apakah kamu yakin Karena const int N = 10; char a[N];berfungsi, dan batas array harus konstanta waktu kompilasi.
fredoverflow
10
Saya yakin sejauh contoh yang saya tulis (diuji masing-masing sebelum memposting). Namun kompiler saya tidak membiarkan saya mengkonversi PI1ke konstanta integral kompilasi-waktu untuk digunakan dalam array, tetapi tidak untuk digunakan sebagai parameter template integral non-tipe. Jadi konvertibilitas waktu kompilasi PI1menjadi tipe integral sepertinya sedikit hit & miss bagi saya.
Howard Hinnant
34
@ FredOverflow: Indeks array non-const telah "bekerja" selama sekitar satu dekade (ada misalnya ekstensi g ++ untuk itu), tetapi itu tidak berarti itu legal C ++ (meskipun beberapa standar C atau C ++ baru-baru ini membuatnya legal , saya lupa yang mana). Adapun perbedaan dalam konstanta compiletime, parameter template dan digunakan sebagai enumpenginisialisasi adalah dua perbedaan penting antara constdan constexpr(dan tidak berfungsi untuk apa pun double).
Damon
17
Paragraf 4 dari 5.19 Ekspresi konstan [expr.const] juga merupakan (non-normatif) catatan yang terkenal menguraikan bahwa implementasi diperbolehkan untuk melakukan aritmatika titik-mengambang berbeda (misalnya berkenaan dengan akurasi) pada waktu kompilasi daripada pada saat runtime. Jadi 1 / PI1dan 1 / PI2dapat menghasilkan hasil yang berbeda. Saya rasa teknisitas ini tidak sepenting saran dalam jawaban ini.
Luc Danton
4
Tapi itu constexpr double PI3 = PI1;bekerja dengan baik untukku. (MSVS2013 CTP). Apa yang saya lakukan salah?
NuPagadi
77
Tidak ada perbedaan di sini, tetapi penting ketika Anda memiliki tipe yang memiliki konstruktor.
struct S {constexpr S(int);};const S s0(0);constexpr S s1(1);
s0adalah konstanta, tetapi tidak berjanji untuk diinisialisasi pada waktu kompilasi. s1ditandai constexpr, sehingga konstanta dan, karena Skonstruktor juga ditandai constexpr, ia akan diinisialisasi pada waktu kompilasi.
Sebagian besar ini penting ketika inisialisasi saat runtime akan memakan waktu dan Anda ingin mendorong pekerjaan itu ke kompiler, di mana itu juga memakan waktu, tetapi tidak memperlambat waktu eksekusi dari program yang dikompilasi
Saya setuju: kesimpulan yang saya dapatkan adalah yang constexprakan mengarah pada diagnosis seandainya perhitungan waktu kompilasi objek tidak mungkin dilakukan. Yang kurang jelas adalah apakah suatu fungsi yang mengharapkan parameter konstan dapat dieksekusi pada waktu kompilasi seandainya parameter tersebut dinyatakan constdan bukan sebagai constexpr: yaitu, akan constexpr int foo(S)dieksekusi pada waktu kompilasi jika saya memanggil foo(s0)?
Matthieu M.
4
@ MatthieuM: Saya ragu apakah foo(s0)akan dieksekusi pada waktu kompilasi, tetapi Anda tidak pernah tahu: kompiler diperbolehkan untuk melakukan optimasi seperti itu. Tentu saja, baik gcc 4.7.2 atau clang 3.2 tidak mengizinkan saya untuk mengkompilasiconstexpr a = foo(s0);
rici
50
constexpr menunjukkan nilai yang konstan dan dikenal selama kompilasi. const menunjukkan nilai yang hanya konstan; tidak wajib mengetahui selama kompilasi.
int sz;constexprauto arraySize1 = sz;// error! sz's value unknown at compilation
std::array<int, sz> data1;// error! same problemconstexprauto arraySize2 =10;// fine, 10 is a compile-time constant
std::array<int, arraySize2> data2;// fine, arraySize2 is constexpr
Perhatikan bahwa const tidak menawarkan jaminan yang sama dengan constexpr, karena objek const tidak perlu diinisialisasi dengan nilai-nilai yang diketahui selama kompilasi.
int sz;constauto arraySize = sz;// fine, arraySize is const copy of sz
std::array<int, arraySize> data;// error! arraySize's value unknown at compilation
Semua objek constexpr adalah const, tetapi tidak semua objek const adalah constexpr.
Jika Anda ingin kompiler menjamin bahwa variabel memiliki nilai yang dapat digunakan dalam konteks yang membutuhkan konstanta waktu kompilasi, alat untuk meraihnya adalah constexpr, bukan const.
Saya sangat menyukai penjelasan Anda..bisakah Anda bisa berkomentar lebih banyak tentang Di mana kasus-kasus yang mungkin perlu kita gunakan untuk mengkompilasi konstanta waktu dalam skenario kehidupan nyata.
Sebuah constexpr simbolik konstan harus diberikan nilai yang diketahui pada waktu kompilasi. Sebagai contoh:
constexprint max =100;void use(int n){constexprint c1 = max+7;// OK: c1 is 107constexprint c2 = n+7;// Error: we don’t know the value of c2// ...}
Untuk menangani kasus di mana nilai "variabel" yang diinisialisasi dengan nilai yang tidak diketahui pada waktu kompilasi tetapi tidak pernah berubah setelah inisialisasi, C ++ menawarkan bentuk konstanta kedua ( konstanta ). Sebagai contoh:
constexprint max =100;void use(int n){constexprint c1 = max+7;// OK: c1 is 107constint c2 = n+7;// OK, but don’t try to change the value of c2// ...
c2 =7;// error: c2 is a const}
" Variabel const " seperti itu sangat umum karena dua alasan:
C ++ 98 tidak memiliki constexpr, jadi orang menggunakan const .
Daftar item "Variabel" yang bukan ekspresi konstan (nilainya tidak diketahui pada waktu kompilasi) tetapi tidak mengubah nilai setelah inisialisasi itu sendiri sangat berguna.
Referensi: "Pemrograman: Prinsip dan Praktek Menggunakan C ++" oleh Stroustrup
Mungkin Anda seharusnya menyebutkan bahwa teks dalam jawaban Anda diambil kata demi kata dari "Pemrograman: Prinsip dan Praktek Menggunakan C ++" oleh Stroustrup
Jawaban:
Saya percaya ada perbedaan. Mari kita ganti namanya sehingga kita bisa membicarakannya lebih mudah:
Kedua
PI1
danPI2
yang konstan, yang berarti Anda tidak bisa mengubah mereka. Namun hanyaPI2
konstanta waktu kompilasi. Ini akan diinisialisasi pada waktu kompilasi.PI1
dapat diinisialisasi pada waktu kompilasi atau waktu berjalan. Selain itu, hanyaPI2
dapat digunakan dalam konteks yang memerlukan konstanta waktu kompilasi. Sebagai contoh:tapi:
dan:
tapi:
Seperti yang harus Anda gunakan? Gunakan mana yang memenuhi kebutuhan Anda. Apakah Anda ingin memastikan bahwa Anda memiliki konstanta waktu kompilasi yang dapat digunakan dalam konteks di mana konstanta waktu kompilasi diperlukan? Apakah Anda ingin dapat menginisialisasi dengan perhitungan yang dilakukan saat run time? Dll
sumber
const int N = 10; char a[N];
berfungsi, dan batas array harus konstanta waktu kompilasi.PI1
ke konstanta integral kompilasi-waktu untuk digunakan dalam array, tetapi tidak untuk digunakan sebagai parameter template integral non-tipe. Jadi konvertibilitas waktu kompilasiPI1
menjadi tipe integral sepertinya sedikit hit & miss bagi saya.enum
penginisialisasi adalah dua perbedaan penting antaraconst
danconstexpr
(dan tidak berfungsi untuk apa pundouble
).1 / PI1
dan1 / PI2
dapat menghasilkan hasil yang berbeda. Saya rasa teknisitas ini tidak sepenting saran dalam jawaban ini.constexpr double PI3 = PI1;
bekerja dengan baik untukku. (MSVS2013 CTP). Apa yang saya lakukan salah?Tidak ada perbedaan di sini, tetapi penting ketika Anda memiliki tipe yang memiliki konstruktor.
s0
adalah konstanta, tetapi tidak berjanji untuk diinisialisasi pada waktu kompilasi.s1
ditandaiconstexpr
, sehingga konstanta dan, karenaS
konstruktor juga ditandaiconstexpr
, ia akan diinisialisasi pada waktu kompilasi.Sebagian besar ini penting ketika inisialisasi saat runtime akan memakan waktu dan Anda ingin mendorong pekerjaan itu ke kompiler, di mana itu juga memakan waktu, tetapi tidak memperlambat waktu eksekusi dari program yang dikompilasi
sumber
constexpr
akan mengarah pada diagnosis seandainya perhitungan waktu kompilasi objek tidak mungkin dilakukan. Yang kurang jelas adalah apakah suatu fungsi yang mengharapkan parameter konstan dapat dieksekusi pada waktu kompilasi seandainya parameter tersebut dinyatakanconst
dan bukan sebagaiconstexpr
: yaitu, akanconstexpr int foo(S)
dieksekusi pada waktu kompilasi jika saya memanggilfoo(s0)
?foo(s0)
akan dieksekusi pada waktu kompilasi, tetapi Anda tidak pernah tahu: kompiler diperbolehkan untuk melakukan optimasi seperti itu. Tentu saja, baik gcc 4.7.2 atau clang 3.2 tidak mengizinkan saya untuk mengkompilasiconstexpr a = foo(s0);
constexpr menunjukkan nilai yang konstan dan dikenal selama kompilasi.
const menunjukkan nilai yang hanya konstan; tidak wajib mengetahui selama kompilasi.
Perhatikan bahwa const tidak menawarkan jaminan yang sama dengan constexpr, karena objek const tidak perlu diinisialisasi dengan nilai-nilai yang diketahui selama kompilasi.
Semua objek constexpr adalah const, tetapi tidak semua objek const adalah constexpr.
Jika Anda ingin kompiler menjamin bahwa variabel memiliki nilai yang dapat digunakan dalam konteks yang membutuhkan konstanta waktu kompilasi, alat untuk meraihnya adalah constexpr, bukan const.
sumber
Sebuah constexpr simbolik konstan harus diberikan nilai yang diketahui pada waktu kompilasi. Sebagai contoh:
Untuk menangani kasus di mana nilai "variabel" yang diinisialisasi dengan nilai yang tidak diketahui pada waktu kompilasi tetapi tidak pernah berubah setelah inisialisasi, C ++ menawarkan bentuk konstanta kedua ( konstanta ). Sebagai contoh:
" Variabel const " seperti itu sangat umum karena dua alasan:
Referensi: "Pemrograman: Prinsip dan Praktek Menggunakan C ++" oleh Stroustrup
sumber