2013-07-05 17 views
6

Poniższy kod wygląda uzasadnione, ale nie skompilowaćprzekazując funkcję jako parametr do metody szablonu klasy szablonu

void f() {} 

template<bool> 
struct call_any 
{ 
    template<typename F> 
    static void call(F f) {} 
}; 

template<bool B> 
void call_f() 
{ 
    call_any<true>::call<void (&)()>(f); // OK 
    call_any<false>::call<void (&)()>(f); // OK 
    call_any<B>::call<void()>(f);   // OK 
    call_any<B>::call<void (&)()>(f); // expected primary-expression before '>' 
} 

Dlaczego występuje błąd i co to znaczy?

Odpowiedz

10

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.

Powiązane problemy