Apakah ada perbedaan antara definisi berikut?
const double PI = 3.141592653589793;
constexpr double PI = 3.141592653589793;
Jika tidak, gaya mana yang lebih disukai dalam C ++ 11?
Apakah ada perbedaan antara definisi berikut?
const double PI = 3.141592653589793;
constexpr double PI = 3.141592653589793;
Jika tidak, gaya mana yang lebih disukai dalam C ++ 11?
Jawaban:
Saya percaya ada perbedaan. Mari kita ganti namanya sehingga kita bisa membicarakannya lebih mudah:
const double PI1 = 3.141592653589793;
constexpr double PI2 = 3.141592653589793;
Kedua PI1
dan PI2
yang konstan, yang berarti Anda tidak bisa mengubah mereka. Namun hanya PI2
konstanta waktu kompilasi. Ini akan diinisialisasi pada waktu kompilasi. PI1
dapat diinisialisasi pada waktu kompilasi atau waktu berjalan. Selain itu, hanya PI2
dapat digunakan dalam konteks yang memerlukan konstanta waktu kompilasi. Sebagai contoh:
constexpr double PI3 = PI1; // error
tapi:
constexpr double PI3 = PI2; // ok
dan:
static_assert(PI1 == 3.141592653589793, ""); // error
tapi:
static_assert(PI2 == 3.141592653589793, ""); // ok
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
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 kompilasi PI1
menjadi tipe integral sepertinya sedikit hit & miss bagi saya.
enum
penginisialisasi adalah dua perbedaan penting antara const
dan constexpr
(dan tidak berfungsi untuk apa pun double
).
1 / PI1
dan 1 / 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.
struct S {
constexpr S(int);
};
const S s0(0);
constexpr S s1(1);
s0
adalah konstanta, tetapi tidak berjanji untuk diinisialisasi pada waktu kompilasi. s1
ditandai constexpr
, sehingga konstanta dan, karena S
konstruktor 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
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 dinyatakan const
dan bukan sebagai constexpr
: yaitu, akan constexpr int foo(S)
dieksekusi pada waktu kompilasi jika saya memanggil foo(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.
int sz;
constexpr auto arraySize1 = sz; // error! sz's value unknown at compilation
std::array<int, sz> data1; // error! same problem
constexpr auto 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;
const auto 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.
Sebuah constexpr simbolik konstan harus diberikan nilai yang diketahui pada waktu kompilasi. Sebagai contoh:
constexpr int max = 100;
void use(int n)
{
constexpr int c1 = max+7; // OK: c1 is 107
constexpr int 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:
constexpr int max = 100;
void use(int n)
{
constexpr int c1 = max+7; // OK: c1 is 107
const int 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:
Referensi: "Pemrograman: Prinsip dan Praktek Menggunakan C ++" oleh Stroustrup