C ++ 17 memperkenalkan variabel inline
C ++ 17 memperbaiki masalah ini untuk constexpr static
variabel anggota yang membutuhkan definisi out-of-line jika itu digunakan odr. Lihat bagian kedua dari jawaban ini untuk detail pra-C ++ 17.
Proposal P0386 Inline Variables memperkenalkan kemampuan untuk menerapkan inline
specifier ke variabel. Khususnya untuk kasus ini constexpr
menyiratkan inline
untuk variabel anggota statis. Proposal itu mengatakan:
Specifier sebaris dapat diterapkan ke variabel serta fungsi. Variabel yang dideklarasikan sebaris memiliki semantik yang sama dengan fungsi yang dinyatakan sebaris: ia dapat didefinisikan, secara identik, dalam beberapa unit terjemahan, harus didefinisikan dalam setiap unit terjemahan yang digunakan odr, dan perilaku program adalah seolah-olah hanya ada satu variabel.
dan memodifikasi [basic.def] p2:
Deklarasi adalah definisi kecuali
...
- itu menyatakan anggota data statis di luar definisi kelas dan variabel didefinisikan dalam kelas dengan specifier constexpr (penggunaan ini sudah ditinggalkan; lihat [depr.static_constexpr]),
...
dan tambahkan [depr.static_constexpr] :
Untuk kompatibilitas dengan Standar Internasional C ++ sebelumnya, anggota data statis constexpr dapat redundansi redundansi di luar kelas tanpa inisialisasi. Penggunaan ini sudah usang. [Contoh:
struct A {
static constexpr int n = 5; // definition (declaration in C++ 2014)
};
constexpr int A::n; // redundant declaration (definition in C++ 2014)
- contoh akhir]
C ++ 14 dan sebelumnya
Dalam C ++ 03, kami hanya diizinkan untuk menyediakan inisialisasi kelas untuk jenis integral integral atau enumerasi , dalam C ++ 11 menggunakan constexpr
ini diperluas ke tipe literal .
Dalam C ++ 11, kita tidak perlu memberikan definisi lingkup namespace untuk anggota statis constexpr
jika tidak digunakan , kita dapat melihat ini dari draft bagian standar C ++ 11 9.4.2
[class.static.data] yang mengatakan ( tekankan tambang ke depan ):
[...] Anggota data statis dari tipe literal dapat dideklarasikan dalam definisi kelas dengan specifier constexpr; jika demikian, deklarasi harus menentukan inisialisasi brace-atau-sama-di mana setiap klausa initializer yang merupakan tugas-ekspresi adalah ekspresi konstan. [Catatan: Dalam kedua kasus ini, anggota dapat muncul dalam ekspresi konstan. —Kirim catatan]
Anggota harus tetap didefinisikan dalam lingkup namespace jika digunakan odr (3.2) dalam program dan definisi lingkup namespace tidak boleh mengandung inisialisasi.
Jadi kemudian pertanyaannya adalah, apakah yang baz
digunakan di sini:
std::string str(baz);
dan jawabannya adalah ya , jadi kami memerlukan definisi lingkup namespace juga.
Jadi bagaimana kita menentukan apakah suatu variabel digunakan odr ? C ++ 11 yang asli kata-kata di bagian 3.2
[basic.def.odr] mengatakan:
Ekspresi berpotensi dievaluasi kecuali operan yang tidak dievaluasi (Klausul 5) atau subekspresi daripadanya. Variabel yang namanya muncul sebagai ekspresi yang berpotensi dievaluasi adalah odr-digunakan kecuali
itu adalah objek yang memenuhi persyaratan untuk muncul dalam ekspresi konstan (5.19) dan konversi nilai-ke-nilai (4.1) segera diterapkan .
Begitu baz
juga menghasilkan ekspresi konstan tetapi konversi lvalue ke rvalue tidak segera diterapkan karena tidak berlaku karena baz
menjadi array. Ini tercakup dalam bagian4.1
[conv.lval] yang mengatakan:
Nilai (3,10) dari tidak berfungsinya, T-non-array tipe dapat dikonversi ke nilai awal.53 [...]
Apa yang diterapkan dalam konversi array-to-pointer .
Kata-kata [basic.def.odr] ini diubah karena Laporan Cacat 712 karena beberapa kasus tidak dicakup oleh kata-kata ini tetapi perubahan ini tidak mengubah hasil untuk kasus ini.