Saya memiliki kode berikut:
template <typename TC>
class C
{
struct S
{
template <typename TS>
void fun() const
{}
};
void f(const S& s)
{
s.fun<int>();
}
};
// Dummy main function
int main()
{
return 0;
}
Saat membuat ini dengan gcc 9.2 dan dentang (9.0), saya mendapatkan kesalahan kompilasi karena template
kata kunci diperlukan untuk memohon fun
. Dentang menunjukkan:
error: use 'template' keyword to treat 'fun' as a dependent template name
s.fun<int>();
^
template
Saya tidak mengerti mengapa kompiler berpikir fun
adalah nama dependen dalam konteks f
, karena f
bukan template itu sendiri. Jika saya berubah C
menjadi kelas reguler alih-alih templat, kesalahan hilang; Namun, saya tidak melihat mengapa harus ada kesalahan sejak awal karena keduanya S
tidak f
bergantung TC
.
Anehnya, MSVC 19.22 mengkompilasi ini dengan baik.
catatan
Sebelum pemungutan suara ditutup sebagai dupe dari Di mana dan mengapa saya harus meletakkan kata kunci "templat" dan "ketik nama"? tolong pertimbangkan ini adalah kasus khusus di mana bahkan jika S
memang nama dependen, dalam konteks f
itu tidak akan tergantung jika bukan karena fakta bahwa mereka adalah anggota Instansiasi saat ini.
Jawaban:
Pertimbangkan :
s.a<0>(i)
diuraikan sebagai ekspresi yang berisi dua operasi perbandingan<
dan>
, dan ini baik untuk # 1 tetapi gagal untuk # 2.Jika ini diubah untuk
s.template a<0>(i)
kemudian # 2 adalah OK dan # 1 gagal. Dengan demikiantemplate
kata kunci tidak pernah berlebihan di sini.MSVC mampu menafsirkan ekspresi
s.a<0>(i)
dua arah dalam program yang sama. Tetapi ini tidak benar menurut Standar; setiap ekspresi seharusnya hanya memiliki satu parse untuk ditangani oleh kompiler.sumber
C
atau yang lain, tetapi Anda tidak dapat membuat instantiate keduanya. Katatemplate
kunci di sini adalah IMHO yang tidak dibutuhkan, karena yangS
dipilih tergantung pada yangC
Anda instantiate. Tanpatemplate
kata kunci, Anda dapat meng-instantiate keduanya, dan perilaku f akan berbeda untuk setiap instance.<
tidak menjadi operator perbandingan dalam satu instantiasi templat dan braket sudut pembuka di instantiasi lain. Ini untuk memastikan bahwa kompiler dapat mem-parsing templat ke AST (dengan placeholder untuk tipe templat).fun
mungkin atau mungkin bukan fungsi templat (atau mungkin tidak ada sama sekali) tergantung pada parameter templatclass C
.Itu karena Anda dapat berspesialisasi
S
(tanpa berspesialisasiC
):Karena kompiler ingin tahu apakah
fun
template atau tidak ketika pertama kali melihatclass C
(sebelum mengganti parameter template),template
diperlukan.sumber
S
dapat diakses olehf
. Jika mereka tidak bisa, pembatasan ini tidak masuk akal karenaf
tidak akan dapat melihatnya lagi.f
menemukannya.