2010-09-04 15 views
20

Warum kann das nicht kompiliert werden? (G ++ - 4,5)Adresse der C++ - Vorlagenfunktion

template < typename U > 
static void h() { 
} 

int main() { 
    auto p = &h<int>; // error: p has incomplete type 
} 

EDIT: Hier ist ein Work-around:

template < typename U > 
static void h() { 
} 

int main() { 
    typedef decltype (&h<int>) D; 
    D p = &h<int>; // works 
} 
+1

Kompiliert auf Visual Studio 2010. Es ist wahrscheinlich ein Fehler in GCC. Was Sie versuchen könnten, ist 'declltype (& h ) p = & h ;' – Puppy

+0

Funktioniert mit mindestens G ++ 4.6. – Maister

+0

@DeadMG: Ohne "auto" gibt es sogar keine Notwendigkeit, dedef, 'void (* p)() = & h ;' würde auch kompilieren. – doc

Antwort

13

In C++ 0x ist dies garantiert zu arbeiten. In C++ 03 funktionierte das jedoch nicht (der Initialisierungsteil, das ist) und einige Compiler unterstützen es anscheinend noch nicht.

Darüber hinaus erinnere ich mich, dass die C++ 0x Formulierung nicht klar ist, was passiert mit &h<int>, wenn es ein Argument für eine Funktionsvorlage ist und der entsprechende Parameter abgeleitet wird (das ist, was auto übersetzt wird, konzeptionell). Die Absicht ist jedoch, dass sie gültig ist. Siehe this defect report, wo sie die Formulierung, das Beispiel von "Nico Josuttis" und ihr letztes Beispiel entworfen haben.

Es gibt eine weitere Regel, die der Wortlaut erzwingt, aber Compiler nicht korrekt implementieren. Zum Beispiel see this clang PR.

0

Es ist nicht kompiliert, da Art von 'p' bekannt ist, nicht an den Compiler, ein absolutes Muss in C++ im Gegensatz zu einigen anderen Sprachen.

Versuchen

template < typename U > 
static void h() { 
} 

int main() { 
    auto void (*p)() = &h<int>; 
} 
+1

Das Schlüsselwort 'auto' wird zum automatischen Typabzug verwendet. Ein C++ 0x-Feature. – dirkgently

+0

Ok, aber in meinem echten Code nimmt h viele andere Parameter an, die von U und anderen Vorlagen abhängen, und ich möchte sie nicht alle angeben, da der Typ von p dem Compiler bekannt sein sollte. – Thomas

+1

@dirkgenly: Oh. Ich bin immer noch bei C++ 03, wo 'auto' für automatische Variablen ist – Chubsdad

0

Versuchen

auto p = static_cast<void(*)()>(& h<int>); 

Da gcc behandelt Funktion als überlastet ein Templat. Aus Sicht des GCC ist es so, als hätten Sie h(int param) und - welchen muss der Compiler wählen?

Ich bemerkte, was das Problem in älteren Versionen von gcc war, aber ich werde versuchen, es ausführlicher zu erklären. GCC konnte den Typ nicht ableiten, da die Template-Funktion wie eine überladene Funktion behandelt wurde. Es war im Grunde wie Sie die folgenden würde:

void h(int) 
{ 
} 

void h(float) 
{ 
} 

void (*p)(int) = & h; //ok 
void (*p)(float) = & h; //ok 
auto p = & h; //error: which version of h? 

Für gcc h<int> war wie überlastet h Funktion mit endlosen Alternativen abhängig von T Parameter. Mit dem in Frage gestellten Code war es O.K. Folgendes zu tun:

void (*p)() = & h<int>; 

(das ist, warum ich nicht bekommen typedefed "work-around")

Wie ich dachte OP C++ 11 auto Schlüsselwort verwenden wollte, wie durch einen Tag vorgeschlagen, Ich statisch h<int>void(*)() gegossen, die Art von No-Operation ist, nur um gcc Trick, weil es nicht in der Lage war, mit Vorlagenfunktionen und auto richtig umzugehen.

Die Funktionen void h<int>() und void h<float>() sollten natürlich wie verschiedene Funktionen mit dem gleichen Zeigertyp behandelt werden und nicht überladen Versionen von h Funktion.Wenn instanziiert sollten sie wie void hInt() und void hFloat() verhalten und Sie sollten Auto zu benutzen, wie hier in der Lage:

void hInt() 
{ 
} 

void hFloat() 
{ 
} 

auto p = hInt; 
p = hFloat; 

Aber für gcc aus irgendeinem Grund sie waren wie überladene Versionen von h.

Bitte geben Sie einen Grund für downvotes.

+0

Ich bin nicht der downvoter :) Jedenfalls bin ich mir nicht sicher, ob du deine Logik verstehst: da du static_casting zu einer Kompilierzeit bekannten Typs bist, was nützt das für auto? – Francesco

+0

@Francesco: ohne eine Besetzung gcc wirft einen Fehler "Anweisung kann die Adresse der überladenen Funktion nicht auflösen". Sie erhalten den gleichen Fehler im Falle einer überladenen Funktion (wie 'void h (int)' und 'void h (float)'). In diesem Fall kann der Compiler nicht bestimmen, welche Version er wählen soll, wenn er die Anweisung '& h' findet . Aus irgendeinem Grund (ich denke, es ist etwas mit Template Argumenten Discovery) Template-Funktion ist behandeln auf die gleiche Weise wie überladen. Nachdem ich wie in einem Fall überladener Funktionen static_cast benutzt hatte, begann es zu kompilieren. 'auto' wird verwendet, um' p'-Typ abzuleiten. – doc

+0

@Francesco: Sie haben das gleiche Ergebnis mit 'typedef' wie mit einem static_cast. Ich dachte, er wollte C++ 0x 'Auto' Schlüsselwort ... – doc