Saya mencoba memahami cuplikan kode berikut
Cuplikan # 1
template <typename T>
struct A
{
static constexpr int VB = T::VD;
};
struct B : A<B>
{
};
Baik gcc9 atau dentang melemparkan kesalahan di sini.
Q. Mengapa kode ini dikompilasi? Bukankah kita instantiasi A<B>
ketika mewarisi dari B? Tidak ada VD di B, jadi bukankah seharusnya kompiler membuat kesalahan di sini?
Cuplikan # 2
template <typename T>
struct A
{
static constexpr auto AB = T::AD; // <- No member named AD in B
};
struct B : A<B>
{
static constexpr auto AD = 0xD;
};
Dalam hal ini, gcc9 mengkompilasi dengan baik tetapi clang9 melempar kesalahan dengan mengatakan "Tidak ada anggota bernama AD dalam B".
P. Mengapa kompilasi dengan gcc9 / mengapa tidak dikompilasi dengan clang9?
Cuplikan # 3
template <typename T>
struct A
{
using TB = typename T::TD;
};
struct B : A<B>
{
using TD = int;
};
Di sini clang9 dan gcc9 melempar kesalahan. gcc9 mengatakan "penggunaan tidak valid tipe struct 'B' tidak lengkap.
Q. Jika struct B tidak lengkap di sini maka mengapa tidak lengkap di snippet # 2?
Compiler bendera yang digunakan: -std=c++17 -O3 -Wall -Werror
. Terima kasih sebelumnya!!!
sumber
struct B
instantiatingA
denganB
?B
tidak lengkap ... Tetapi tidak yakin kapan anggota harus dipakai.Jawaban:
Saya percaya ini pada dasarnya mendidih ke [temp.inst] / 2 (penekanan milik saya):
dan [temp.inst] / 9
Kata-kata dalam standar tentang instantiasi template implisit membuat banyak detail terbuka untuk interpretasi. Secara umum, bagi saya tampaknya Anda tidak bisa mengandalkan bagian-bagian dari template yang tidak sedang dipakai kecuali spesifikasi secara eksplisit mengatakan demikian. Jadi:
Cuplikan # 1
Anda sedang instantiating
A<B>
. Tapi instantiatingA<B>
hanya instantiate deklarasi, bukan definisi anggota data statisnya.VB
tidak pernah digunakan dengan cara yang akan membutuhkan definisi yang ada. Kompiler harus menerima kode ini.Cuplikan # 2
Seperti yang ditunjukkan oleh Jarod42, deklarasi
AB
berisi tipe placeholder. Tampak bagi saya bahwa kata-kata dari standar tidak benar-benar jelas tentang apa yang seharusnya terjadi di sini. Apakah instantiasi deklarasi anggota data statis yang berisi tipe placeholder memicu pengurangan tipe placeholder dan, dengan demikian, merupakan penggunaan yang memerlukan definisi anggota data statis? Saya tidak dapat menemukan kata-kata dalam standar yang jelas akan mengatakan ya atau tidak pada itu. Jadi, saya akan mengatakan bahwa kedua interpretasi sama-sama valid di sini dan, dengan demikian, GCC dan dentang keduanya benar ...Cuplikan # 3
Sebuah jenis kelas hanya selesai pada titik di mana Anda mencapai penutupan
}
dari kelas-specifier [class.mem] / 6 . Dengan demikian,B
tidak lengkap selama instantiasi implisitA<B>
dalam semua cuplikan Anda. Hanya saja ini tidak relevan untuk Cuplikan # 1. Dalam Cuplikan # 2, dentang memang memberi Anda kesalahanNo member named AD in B
sebagai hasilnya. Mirip dengan kasus Snippet # 2, saya tidak dapat menemukan kata-kata kapan tepatnya anggota alias deklarasi akan dipakai. Namun, tidak seperti definisi anggota data statis, tidak ada kata-kata di tempat untuk secara eksplisit mencegah instantiasi alias deklarasi anggota selama instantiasi implisit templat kelas. Jadi, saya akan mengatakan bahwa perilaku GCC dan dentang adalah interpretasi yang valid dari standar dalam kasus ini ...sumber
constexpr
anggota data statis hanya deklarasi. C ++ 17 memperolehinline
variabel danconstexpr
menyiratkaninline
, dan ini membuat definisi anggota data statis dalam tubuh definisi.auto
kasus tersebut, aturan mengatakan bahwa deklarasi harus merupakan deklarasi inisialisasi. Ini hanya bisa terjadi jika diketahui bahwa deklarasi adalah definisi (sejauh yang saya tahu .. Saya sudah keluar dari tanah pengacara untuk sementara waktu). Di masa lalu, ada kasus serupa dan eel.is/c++draft/temp.inst#2.sentence-3 ditambahkan, di mana deklarasi itu definisi yang dipakai sebagai "dikenal sebagai definisi" tanpa sebenarnya instantiating definisi.