Kode berikut cukup sepele dan saya berharap itu harus dikompilasi dengan baik.
struct A
{
struct B
{
int i = 0;
};
B b;
A(const B& _b = B())
: b(_b)
{}
};
Saya telah menguji kode ini dengan g ++ versi 4.7.2, 4.8.1, clang ++ 3.2 dan 3.3. Terlepas dari kenyataan bahwa g ++ 4.7.2 segfaults pada kode ini ( http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57770 ), kompiler lain yang diuji memberikan pesan kesalahan yang tidak menjelaskan banyak.
g ++ 4.8.1:
test.cpp: In constructor ‘constexpr A::B::B()’:
test.cpp:3:12: error: constructor required before non-static data member for ‘A::B::i’ has been parsed
struct B
^
test.cpp: At global scope:
test.cpp:11:23: note: synthesized method ‘constexpr A::B::B()’ first required here
A(const B& _b = B())
^
clang ++ 3.2 dan 3.3:
test.cpp:11:21: error: defaulted default constructor of 'B' cannot be used by non-static data member initializer which appears before end of class definition
A(const B& _b = B())
^
Membuat kode ini dapat dikompilasi adalah mungkin dan sepertinya tidak ada bedanya. Ada dua pilihan:
struct B
{
int i = 0;
B(){} // using B()=default; works only for clang++
};
atau
struct B
{
int i;
B() : i(0) {} // classic c++98 initialization
};
Apakah kode ini benar-benar salah atau apakah penyusunnya salah?
c++
c++11
language-lawyer
etam1024
sumber
sumber
internal compiler error: Segmentation fault
ke kode ini ...int i = 0
kecuali jika memang demikianstatic const int i = 0
.B()
sebagai panggilan fungsi ke konstruktor. Anda tidak pernah secara langsung "memanggil" konstruktor. Pikirkan ini sebagai sintaks khusus yang membuat sementaraB
... dan konstruktor dipanggil hanya sebagai satu bagian dari proses itu, jauh di dalam mekanisme yang mengikutinya.B
tampaknya membuat ini berfungsigcc 4.7
.Jawaban:
Baik. Standar memiliki cacat - ia mengatakan bahwa keduanya
A
dianggap lengkap saat mengurai penginisialisasi untukB::i
, dan yangB::B()
(yang menggunakan penginisialisasi untukB::i
) dapat digunakan dalam definisiA
. Itu jelas siklik. Pertimbangkan ini:struct A { struct B { int i = (A(), 0); }; A() noexcept(!noexcept(B())); };
Ini memiliki kontradiksi:
B::B()
secara implisitnoexcept
IFFA()
tidak melempar, danA()
tidak membuang IFFB::B()
adalah tidaknoexcept
. Ada sejumlah siklus dan kontradiksi lain di area ini.Ini dilacak oleh masalah inti 1360 dan 1397 . Secara khusus perhatikan catatan ini dalam masalah inti 1397:
Itu adalah kasus khusus dari aturan yang saya terapkan di Clang untuk mengatasi masalah ini. Aturan Clang adalah bahwa konstruktor default default untuk kelas tidak dapat digunakan sebelum penginisialisasi anggota data non-statis untuk kelas tersebut diurai. Oleh karena itu, Clang mengeluarkan diagnosis di sini:
A(const B& _b = B()) ^
... karena Clang mem-parsing argumen default sebelum mem-parsing penginisialisasi default, dan argumen default ini akan mengharuskan
B
penginisialisasi default sudah diurai (untuk mendefinisikan secara implisitB::B()
).sumber
Mungkin ini masalahnya:
Jadi, konstruktor default dibuat saat pertama kali dicari, tetapi pencarian akan gagal karena A tidak sepenuhnya ditentukan dan B di dalam A tidak akan ditemukan.
sumber
B b
bukan masalah, dan menemukan metode eksplisit / konstruktor yang dideklarasikan secara eksplisitB
bukanlah masalah. Jadi alangkah baiknya untuk melihat beberapa definisi mengapa pencarian harus diproses secara berbeda di sini sehingga "B
di dalamA
tidak ditemukan" hanya dalam satu kasus ini tetapi tidak dalam kasus lainnya, sebelum kita dapat menyatakan kode ilegal karena alasan ini.=0
darii = 0;
. Tetapi tanpa itu=0
, kodenya valid dan Anda tidak akan menemukan kompiler tunggal yang mengeluh tentang penggunaanB()
dalam definisiA
.