2013-07-05 5 views
6

Der folgende Code sieht legitim, aber nicht kompiliertvorbei Funktion als Parameter Template-Methode der Template-Klasse

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 '>' 
} 

Warum es ein Fehler ist und was bedeutet es?

Antwort

10

Wenn Sie mit Typen arbeiten, die von den Vorlagenparametern innerhalb einer Vorlage abhängig sind, weiß der Compiler nicht, welche Arten von Elementen die Elemente dieses Typs sind. Sofern Sie nichts anderes angeben, wird davon ausgegangen, dass die Elemente keine Typen und keine Vorlagen sind. Aus diesem Grund versucht es, < als ein Kleiner-als-Operator zu behandeln, aber es wird unmöglich, den Ausdruck auf diese Weise zu analysieren, wenn er > erreicht.

Um die Fehler beseitigen Sie diese stattdessen verwenden sollten:

call_any<B>::template call<void (&)()>(f); 

Dies teilt dem Compiler ausdrücklich, dass call ist eine Schablone, also sollte es eine der < als Anfang der Template-Parameter behandeln und nicht normaler kleiner als Operator.

Dies sollte template als auch verwenden:

call_any<B>::call<void()>(f); 

Der einzige Grund, warum Sie nicht sehen, den Fehler auf dieser Linie ist, dass es eine Möglichkeit, es als eine nicht-Vorlage zu analysieren ist:

(call_any<B>::call < void()) > (f); 

Obwohl es seltsam ist, ist es syntaktisch gültig, also kommt der Compiler über diese Linie hinaus, und der erste Fehler, den Sie sehen, ist der, den Sie erwähnen. Ohne das Schlüsselwort template würden Sie jedoch schließlich einen Fehler erhalten, sobald call_f tatsächlich instanziiert wurde (wahrscheinlich - es gibt seltsame Wege, wie es funktionieren könnte).

Die ersten beiden Beispiele sind in Ordnung, ohne das Schlüsselwort template zu verwenden. Da der Typ nicht von den Vorlagenparametern abhängig ist, kann festgestellt werden, dass call eine Vorlage ist, während call_f analysiert wird.

Sie könnten fragen: "Warum kann der Compiler nicht herausfinden, dass es eine Vorlage ist? Ich habe es als Vorlage im Code oben definiert!". Das Problem ist Spezialisierung. Sie könnten die Vorlage spezialisieren und tun etwas ganz anderes als das, was die primäre Vorlage angibt:

template<> 
struct call_any<false> 
{ 
    static const int call = 5; 
}; 

Diese Spezialisierung auch auftreten könnten nach call_f definiert ist, so kann der Compiler nicht darauf verlassen, was die primäre Vorlage für call_any sagt, wenn es wird analysiert call_f.