Saya telah bermain dengan clang beberapa saat, dan saya menemukan "test / SemaTemplate / dependent-template-recover.cpp" (dalam distribusi clang) yang seharusnya memberikan petunjuk untuk memulihkan dari kesalahan template.
Semuanya dapat dengan mudah dipreteli menjadi contoh minimal:
template<typename T, typename U, int N> struct X {
void f(T* t)
{
// expected-error{{use 'template' keyword to treat 'f0' as a dependent template name}}
t->f0<U>();
}
};
Pesan kesalahan yang dihasilkan oleh dentang:
tpl.cpp:6:13: error: use 'template' keyword to treat 'f0' as a dependent template name
t->f0<U>();
^
template
1 error generated.
... Tapi saya kesulitan memahami di mana tepatnya seseorang seharusnya memasukkan template
kata kunci agar kode tersebut benar secara sintaksis?
Jawaban:
ISO C ++ 03 14.2 / 4:
In
t->f0<U>();
f0<U>
adalah spesialisasi template anggota yang muncul setelah->
dan yang secara eksplisit bergantung pada parameter templateU
, sehingga spesialisasi template anggota harus diawali dengantemplate
kata kunci.Jadi ganti
t->f0<U>()
ket->template f0<U>()
.sumber
t->(f0<U>())
akan memperbaikinya, karena saya pikir itu akan dimasukkanf0<U>()
ke dalam ekspresi mandiri ... yah, saya pikir salah, tampaknya ...Selain poin yang dibuat orang lain, perhatikan bahwa terkadang compiler tidak dapat mengambil keputusan dan kedua interpretasi dapat menghasilkan program alternatif yang valid saat membuat instance
#include <iostream> template<typename T> struct A { typedef int R(); template<typename U> static U *f(int) { return 0; } static int f() { return 0; } }; template<typename T> bool g() { A<T> a; return !(typename A<T>::R*)a.f<int()>(0); } int main() { std::cout << g<void>() << std::endl; }
Ini dicetak
0
saat menghilangkantemplate
sebelumnyaf<int()>
tetapi1
saat memasukkannya. Saya membiarkannya sebagai latihan untuk mencari tahu apa yang dilakukan kode itu.sumber
f<U>
dan selalu mencetak1
, yang sangat masuk akal bagi saya. Saya masih tidak mengerti mengapatemplate
kata kunci itu diperlukan dan apa bedanya.template
diperlukan: stackoverflow.com/questions/610245/… tanpa hanya mengandalkan istilah standar yang sulit dipahami. Mohon laporkan jika ada jawaban yang masih membingungkan.Masukkan tepat sebelum titik tanda sisipannya:
template<typename T, typename U, int N> struct X { void f(T* t) { t->template f0<U>(); } };
Edit: alasan aturan ini menjadi lebih jelas jika Anda berpikir seperti seorang compiler.
Kompiler umumnya hanya melihat ke depan satu atau dua token sekaligus, dan umumnya tidak "melihat ke depan" ke sisa ekspresi.[Sunting: lihat komentar] Alasan untuk kata kunci ini sama dengan mengapa Anda memerlukantypename
kata kunci untuk menunjukkan nama tipe dependen: ini memberi tahu kompiler "hei, pengenal yang akan Anda lihat adalah nama template, bukan nama anggota data statis diikuti dengan tanda kurang dari ".sumber
template
. Ada kasus di mana dengan dan tanpatemplate
akan menghasilkan program yang valid dengan perilaku berbeda. Jadi ini bukan hanya masalah sintaksis (t->f0<int()>(0)
valid secara sintaksis untuk versi daftar argumen kurang dari dan templat).Kutipan dari C ++ Templates
Konstruksi .template Masalah yang sangat mirip ditemukan setelah pengenalan nama jenis. Perhatikan contoh berikut menggunakan tipe bitet standar:
template<int N> void printBitset (std::bitset<N> const& bs) { std::cout << bs.template to_string<char,char_traits<char>, allocator<char> >(); }
Konstruksi aneh dalam contoh ini adalah .template. Tanpa penggunaan ekstra dari template, compiler tidak akan mengetahui bahwa less-than token (<) yang mengikuti tidak benar-benar "kurang dari" tetapi awal dari daftar argumen template. Perhatikan bahwa ini adalah masalah hanya jika konstruksi sebelum periode bergantung pada parameter template. Dalam contoh kita, parameter bs bergantung pada parameter template N.
Kesimpulannya, notasi .template (dan notasi serupa seperti -> template) harus digunakan hanya di dalam template dan hanya jika mengikuti sesuatu yang bergantung pada parameter template.
sumber