Gdy mamy do czynienia z typami zależnymi od parametrów szablonu w szablonie, kompilator nie wie, jakie typy są członkami tego typu. Jeśli nie określisz inaczej, zakłada się, że członkowie nie są typami, a nie szablonami. Z tego powodu próbuje traktować <
jako operatora mniejszego niż, ale nie jest możliwe przeanalizowanie wyrażenia w ten sposób, zanim dotrze ono do >
.
Aby pozbyć się tego błędu należy użyć zamiast tego:
call_any<B>::template call<void (&)()>(f);
ten informuje kompilator wyraźnie, że call
jest szablon, więc należy go traktować <
jako początek parametrów szablonu i nie zwykły mniejszy niż operator.
Należy używać template
także:
call_any<B>::call<void()>(f);
Jedyny powód, dla którego nie widzisz błąd na tej linii jest to, że istnieje sposób, aby analizować je jako nie-szablonu:
(call_any<B>::call < void()) > (f);
Chociaż jest nieparzysta, jest poprawna pod względem składni, więc kompilator przechodzi obok tej linii, a pierwszy błąd, który widzisz, jest tym, o którym wspomniałeś. Jednak bez słowa kluczowego template
, w końcu otrzymasz błąd po tym, jak call_f
został faktycznie utworzony (prawdopodobnie - są dziwne sposoby, w jakie może działać).
Pierwsze dwa przykłady są w porządku bez użycia słowa kluczowego template
. Ponieważ typ nie zależy od parametrów szablonu, można ustalić, że call
jest szablonem, podczas gdy call_f
jest analizowany.
Możesz zapytać: "Dlaczego kompilator nie może stwierdzić, że jest to szablon? Zdefiniowałem go jako szablon w kodzie tuż powyżej!". Problemem jest specjalizacja. Można specjalizować szablon i zrobić coś zupełnie innego niż to, co określa podstawowy szablon:
template<>
struct call_any<false>
{
static const int call = 5;
};
Ta specjalizacja mogłyby wystąpić nawet po call_f
jest określona, więc kompilator nie może polegać na tym, co pierwotne szablon dla call_any
kiedy mówi to parsowanie call_f
.