Kadang-kadang saya telah melihat beberapa pesan kesalahan yang benar-benar tidak dapat dipahami meludah gcc
ketika menggunakan template ... Secara khusus, saya punya masalah di mana deklarasi yang tampaknya benar menyebabkan kesalahan kompilasi yang sangat aneh yang secara ajaib pergi dengan memprefixing typename
kata kunci ke awal kata kunci. deklarasi ... (Misalnya, minggu lalu, saya mendeklarasikan dua iterator sebagai anggota kelas templated lain dan saya harus melakukan ini) ...
Apa ceritanya typename
?
Jawaban:
Berikut ini adalah kutipan dari buku Josuttis:
sumber
typename
(meskipun tidak semuanya!).Pos BLog milik Stan Lippman menunjukkan: -
Jadi pada dasarnya Stroustrup menggunakan kembali kata kunci kelas tanpa memperkenalkan kata kunci baru yang diubah setelahnya dalam standar karena alasan berikut
Seperti contoh yang diberikan
tata bahasa salah tafsir
T::A *aObj;
sebagai ekspresi aritmatika sehingga kata kunci baru diperkenalkan disebuttypename
itu memerintahkan kompiler untuk memperlakukan pernyataan selanjutnya sebagai deklarasi.
Itulah mengapa kami memiliki keduanya
Anda dapat melihat posting ini , itu pasti akan membantu Anda, saya hanya mengekstrak sebanyak yang saya bisa
sumber
typename
perlu kata kunci baru , jika Anda dapat menggunakan kata kunci yang adaclass
untuk tujuan yang sama?typename
menjadi perlu untuk memperbaiki masalah parsing seperti yang dijelaskan dalam jawaban Naveen dengan mengutip Josuttis. (Saya tidak berpikir memasukkanclass
di tempat ini akan berhasil.) Hanya setelah kata kunci baru diterima untuk kasus ini, itu juga diperbolehkan dalam deklarasi argumen templat ( atau apakah definisi itu? ), Karenaclass
selalu ada sedikit menyesatkan.Pertimbangkan kodenya
Sayangnya, kompiler tidak diharuskan untuk menjadi peramal, dan tidak tahu apakah T :: sometype akan berakhir dengan merujuk pada nama tipe atau anggota statis dari T. Jadi, orang
typename
dapat mengatakannya:sumber
Dalam beberapa situasi di mana Anda merujuk ke anggota yang disebut tipe dependen (artinya "bergantung pada parameter templat"), kompiler tidak selalu dapat secara jelas mendeduksi makna semantik dari konstruk yang dihasilkan, karena ia tidak tahu nama jenis apa itu. (yaitu apakah itu nama tipe, nama anggota data atau nama yang lain). Dalam kasus seperti itu, Anda harus menyamarkan situasi dengan secara eksplisit memberi tahu kompiler bahwa nama itu milik nama ketik yang didefinisikan sebagai anggota dari tipe dependen itu.
Sebagai contoh
Dalam contoh ini kata kunci yang
typename
diperlukan untuk mengkompilasi kode.Hal yang sama terjadi ketika Anda ingin merujuk ke anggota templat dari tipe dependen, yaitu ke nama yang menunjuk templat. Anda juga harus membantu kompiler dengan menggunakan kata kunci
template
, meskipun ditempatkan berbedaDalam beberapa kasus mungkin perlu menggunakan keduanya
(jika saya mendapatkan sintaks dengan benar).
Tentu saja, peran lain dari kata kunci
typename
adalah untuk digunakan dalam deklarasi parameter template.sumber
Rahasianya terletak pada kenyataan bahwa templat dapat dikhususkan untuk beberapa jenis. Ini berarti juga dapat mendefinisikan antarmuka yang sama sekali berbeda untuk beberapa jenis. Misalnya, Anda dapat menulis:
Orang mungkin bertanya mengapa ini berguna dan memang: Itu benar-benar terlihat tidak berguna. Tetapi mengambil diingat bahwa misalnya
std::vector<bool>
denganreference
jenis terlihat sama sekali berbeda dibandingkan lainnyaT
s. Memang itu tidak mengubah jenis darireference
jenis ke sesuatu yang berbeda tetapi tetap saja itu bisa terjadi.Sekarang apa yang terjadi jika Anda menulis templat Anda sendiri menggunakan
test
templat ini . Sesuatu seperti initampaknya tidak apa-apa untuk Anda karena Anda mengharapkan itu
test<T>::ptr
adalah tipe. Tetapi kompiler tidak tahu dan dalam akta dia bahkan disarankan oleh standar untuk mengharapkan yang sebaliknya,test<T>::ptr
bukan tipe. Untuk memberi tahu kompiler apa yang Anda harapkan, Anda harus menambahkantypename
sebelumnya. Template yang benar terlihat seperti iniIntinya: Anda harus menambahkan
typename
sebelum setiap kali Anda menggunakan tipe templat bersarang di templat Anda. (Tentu saja hanya jika parameter templat templat Anda digunakan untuk templat dalam itu.)sumber
Dua kegunaan:
template
kata kunci argumen (bukanclass
)typename
kunci memberi tahu kompiler bahwa pengenal adalah tipe (bukan variabel anggota statis)sumber
Saya pikir semua jawaban telah menyebutkan
typename
kata kunci, digunakan dalam dua kasus berbeda:a) Saat mendeklarasikan parameter tipe template. misalnya
Yang tidak ada perbedaan di antara mereka dan mereka PERSIS sama.
b) Sebelum menggunakan nama tipe dependen bersarang untuk templat.
Yang tidak menggunakan
typename
mengarah ke kesalahan parsing / kompilasi.Apa yang ingin saya tambahkan ke kasus kedua, seperti yang disebutkan dalam buku Scot Meyers Effective C ++ , adalah bahwa ada pengecualian menggunakan
typename
sebelum nama tipe bersarang tergantung . Pengecualian adalah bahwa jika Anda menggunakan nama tipe bersarang tergantung baik sebagai kelas dasar atau dalam daftar inisialisasi anggota , Anda tidak boleh menggunakannya ditypename
sana:Catatan: Menggunakan
typename
untuk kasus kedua (yaitu sebelum nama tipe dependen bersarang) tidak diperlukan sejak C ++ 20.sumber
sumber