Der folgende minimale Code kompiliert und verlinkt in GNU C ++:
%Vor%, aber mit Visual Studio 2008 wird der Fehler
erzeugt %Vor% Offensichtlich ist die ganze Funktionsimplementierung da, aber es scheint, dass der Compiler die Implementierung der Funktion foo
wegwirft. Wenn die kommentierte Zeile aktiviert ist, findet der Linker das Symbol.
Ich denke (wie g ++ es gut kompiliert), das ist ein gültiger Code, also nehme ich an, dass es einen Fehler in VS 2008 gibt, oder mache ich hier etwas falsch? Kennt jemand eine Workaround / Lösung dafür? Der letzte Code muss mit Visual Studio 2008 arbeiten und im realen Code ist es nicht möglich, alle Template-Typ-Kombinationen zu erraten (dh ich kann die Funktionen nicht explizit für alle verfügbaren Typen instanziieren: hier nur T, im echten Code bis zu Es werden 5 Template-Parameter mit beliebigen Klassen verwendet.)
Als Antwort auf die ursprüngliche Frage; Ist das ein Fehler, gibt es Problemumgehungen?
Ja, es sieht so aus, als hätten Sie einen Fehler in VS2008 gefunden, ich habe ihn mit VS2008 und VS2013.2 mit dem gleichen Linker-Fehler getestet. Ich möchte Sie ermutigen, einen Fehlerbericht mit Microsoft einzureichen. Gibt es Workarounds, glaube ich, könnte es sein.
Wie Sie bemerkt haben, sieht es so aus, als ob der Compiler die implizite Instanziierung des Templates foo<int>
irgendwo zwischen dem Zerfall zu void (*Function)(T,void*)
und dem Zeitpunkt, zu dem er zur Verbindungszeit benötigt wird, "verliert". Nachdem ich mit dem Code ein bisschen herumgespielt habe, denke ich, dass es die apply(M)
Vorlage und Microsoft's Template Parsing Techniken beinhalten könnte; da, wenn apply
nur ein int
als Argument apply(int)
(d. h. keine Vorlage) benötigt, scheint es glücklich zu sein, es zu kompilieren und zu verknüpfen.
Um dies zu umgehen, kann der Code wie folgt geändert werden (Hinzufügen des Standardkonstruktors und Ändern des apply
-Aufrufs von einer Instanz von kernel
). Ich weiß, das kann hässlich aussehen; aber es funktioniert um das Problem und kann Ihnen helfen, das Problem in Ihrem Projekt zu umgehen.
Der Code kompiliert und verbindet sich mit VS2008, VS2013 und gcc.
Mit Bezug auf die Kommentare zur ursprünglichen Frage; Warum oder wie funktioniert das mit einem modernen Compiler? Es handelt sich um zwei C ++ - Einrichtungen.
Wenn foo
als Argument für void(*Function)(T,void*)
angegeben wird, findet ein Decay statt und ein Zeiger wird verwendet, als wäre &foo
verwendet worden.
Konvertierung von Funktion zu Zeiger 4.3
1 Ein Wert des Funktionstyps T kann in einen Pr-Wert vom Typ "Zeiger auf T" umgewandelt werden. Das Ergebnis ist ein Zeiger auf die Funktion
Funktion-Zeiger-Konvertierungen verweisen auf Abschnitt 13.4 für zusätzliche Regeln, wenn möglicherweise überladene Funktionen vorhanden sind. Beachten Sie die Details zur Verwendung von &
und den Fall, in dem die Funktion eine Vorlage ist (Hervorhebung meins).
Adresse der überladenen Funktion 13.4
1 Es wird angenommen, dass ein Funktionsschablonenname einen Satz überladener Funktionen bezeichnet ... Dem überladenen Funktionsnamen kann das & amp; Operator .
2 Wenn der Name eine Funktionsvorlage ist, wird Vorlagenargumentabzug durchgeführt (14.8.2.2), und wenn die Argumentableitung erfolgreich ist, wird die resultierende Vorlagenargumentliste zum Generieren einer einzelnen Funktionsvorlage verwendet Spezialisierung, die zu der Menge der überladenen Funktionen hinzugefügt wird.
Gegeben sei der Zeiger und die Ableitung des Compilers vom Typ T
für die Funktion foo
in diesem Fall int
. Der Compiler erzeugt dann den Code für die Funktion void foo(int,void*)
und dann wird dies während des Linkens verwendet.
Implizite Instanziierung 14.7.1
3 Sofern eine Funktionsschablonenspezialisierung nicht explizit instanziiert oder explizit spezialisiert wurde, wird die Funktionsschablonenspezialisierung implizit instanziiert, wenn auf die Spezialisierung in einem Kontext verwiesen wird, der die Existenz einer Funktionsdefinition erfordert.
Zitate aus C ++ WD n3797
Tags und Links c++ visual-studio-2008 templates function-pointers lnk2019