Diberikan templat kelas berikut:
template<typename T>
struct Outer
{
struct Inner;
auto f(Inner) -> void;
};
kami mendefinisikan Inner
secara terpisah untuk setiap spesialisasi Outer
:
template<>
struct Outer<int>::Inner {};
template<>
struct Outer<double>::Inner {};
dan kemudian mendefinisikan fungsi anggota f
sekali untuk semua spesialisasi Outer
:
auto Outer<T>::f(Inner) -> void
{
}
tapi Dentang (9.0.0) mengeluh:
error: variable has incomplete type 'Outer::Inner'
auto Outer<T>::f(Inner) -> void
^
Kami dapat menghindari kesalahan kompilator dengan juga memberikan definisi Inner
untuk semua spesialisasi lainnya dari Outer
:
template<typename T>
struct Outer<T>::Inner {};
atau dengan mendefinisikan f
secara terpisah untuk setiap spesialisasi:
template<>
auto Outer<int>::f(Inner) -> void
{
}
template<>
auto Outer<double>::f(Inner) -> void
{
}
Baik GCC dan MSVC menerima kode awal, yang menimbulkan pertanyaan; apakah ini bug Dentang atau hanya implementasi yang sesuai dari ketiganya?
Inner
untuk semua spesialisasi lainnya dan mendefinisikanf
secara terpisah untuk setiap spesialisasi menyelesaikan kesalahan kompilasi.Inner
adalah yang dilaporkan sebagai tipe yang tidak lengkap meskipun ada definisi untuk setiap spesialisasiOuter
yang disediakan. JelasInner
akan (dengan benar) menjadi tipe yang tidak lengkap jika Anda menghapus definisinya.Jawaban:
Saya percaya Dentang salah untuk menolak kode Anda. Kita harus bertanya pada diri sendiri, bagaimana deklarasi dan definisi fungsi Anda dibandingkan
Dalam contoh ini,
T::Inner
jelas merupakan tipe dependen. Jadi Dentang mungkin tidak menganggap itu tidak lengkap sampai Instansiasi. Apakah hal yang sama berlaku pada contoh Anda? Saya akan mengatakan demikian. Karena kami memiliki ini dalam standar:Jadi peluru pertama dalam paragraf 9 mencakup kasus ini
typename T::Inner
. Itu adalah tipe dependen.Sementara kasing Anda dilindungi oleh peluru kedua.
Outer::Inner
adalah nama yang ditemukan di instance saat iniOuter
, apalagi itu ditemukan di dalamOuter
dirinya sendiri, dan bukan di kelas dasar. Itu membuatnya menjadi anggota tergantung dari Instansiasi saat ini. Nama ini merujuk ke kelas bersarang. Yang berarti semua kondisi dalam peluru kedua berlaku, sehingga membuatOuter::Inner
tipe dependen juga!Karena kita memiliki tipe dependen dalam kedua kasus ini, kompiler harus memperlakukannya sama seperti tipe dependen. Kesimpulan saya adalah bahwa GCC dan MSVC benar.
sumber