Template-Methode in Klasse nicht verfügbar: "no matching function for call to"
-
Ich habe eine Template-Funktion in einer abstrakten Klasse. Ich kriege einen Compiler-Fehler an Stellen, wo ich diese Template-Funktion verwenden möchte (sowohl in der abstr. Klasse selbst als auch in abgeleiteten, konkreten Klassen).
error: no matching function for call to 'DerivedChn::getConcreteMember()'
Deswegen meine Frage:
Gibt es bei Template-Klassenmethoden irgendwelche Besonderheiten die mir nicht bekannt sind, oder liegt der Fehler an einer anderen Stelle?
Das Bsp schaut etwa so aus:
// abstrakte Basisklasse class BaseChnA { public: /* ... */ template <typename T> T* getConcreteMember(); /* ... */ protected: BaseMemberA* m_member; } // ebenfalls in der Headerdatei: template <typename T> T* BaseChnA::getConcreteMember() { /* Implementierung der Template-Funktion */ } // eine nicht-abstrakte abgeleitete Klasse class DerivedChn : public BaseChn { /* ... */ } // C'tor der abgel. Klasse; verwendet die Template-Funktion DerivedChn::DerivedChn() { /* ... */ m_member = new ConcreteMember1; // ist aber Ptr auf BaseMemberA, deshalb geht folgendes nicht: // m_member->doSthSpecial1(); getConcreteMember()->doSthSpecial1(); } // eine abstr. Klasse die als Ptr in BaseChn eingebunden ist class BaseMemberA{} { /* ... */ } // eine von BaseMemberA abgel. Klasse class ConcreteMember1 : public BaseMemberA { /* ... */ void doSthSpecial1(); // diese Methode ist in der Basisklasse "BaseMemberA" nicht bekannt };Die Template-Methode liefert mit Hilfe von m_member einen Objekt-Ptr zurück, und zwar vom konkreten Klassentyp (bspw. ConcreteMember1). Damit kann ich dann in DerivedChn die Funktion doSthSpecial1() aufrufen, was mit dem Basisklassen-Pointer nicht möglich wäre.
Ich verwende die Template-Methode bspw. im Konstruktor von DerivedChn.
-
Zeigt der gepostete Code diesen Fehler auch oder nicht?
-
Ja, bringt er. Natürlich ist mein Minimal-Test-Code etwas umfangreicher als der gepostete.
-
Deine Klasse hat ja auch keine Memberfunktion namens getConcreteMember(). Deine Klasse hat ein Funktionstemplate mit diesem Namen, aber woher soll der Compiler wissen, wie er es spezialisieren soll? Das musst du ihm schon irgendwo sagen.
edit: Deine Beschreibung hört sich irgendwie komisch an. Suchst du vielleicht virtuelle Methoden und Polymorphie? Was soll denn dein Design bezwecken?
-
SeppJ schrieb:
Deine Klasse hat ja auch keine Memberfunktion namens getConcreteMember(). Deine Klasse hat ein Funktionstemplate mit diesem Namen, aber woher soll der Compiler wissen, wie er es spezialisieren soll? Das musst du ihm schon irgendwo sagen.
Du meinst die Implementierung in der Header-Datei? Ich formulier mal ein kleines Bsp. aus:
// ebenfalls in der Headerdatei: template <typename T> T* BaseChnA::getConcreteMember() { /* Implementierung der Template-Funktion */ if(...) return dynamic_cast<ConcreteMember1*>(m_member); else return dynamic_cast<ConcreteMember2*>(m_member); }Reicht das dem Compiler nicht um die Fkt zu kompilieren?
Erst mit dem genauen Typ kann ich dann eine Funktion aufrufen, die nicht in der Basisklasse vorkommt. Das sollte imho dann so aussehen:
getConcreteMember()->doSthSpecial1();Ich muss mich natürlich selbst drum kümmern dass der Cast funktioniert bzw. den Cast vorher überprüfen.
SeppJ schrieb:
edit: Deine Beschreibung hört sich irgendwie komisch an. Suchst du vielleicht virtuelle Methoden und Polymorphie? Was soll denn dein Design bezwecken?
Ja, da hast Du leider Recht. Ist auch keine schöne Lösung sondern ein Workaround, um bereits begangene Fehler ein wenig auszubessern und wurde bereits diskutiert:
http://www.c-plusplus.net/forum/viewtopic-var-p-is-1803156.html#1803156
-
Radix schrieb:
Ja, bringt er. Natürlich ist mein Minimal-Test-Code etwas umfangreicher als der gepostete.
In solchen Fällen sollte auch der gepostete Code in (ansonsten) compilierbaren Zustand sein, um den Fehler eindeutig identifizieren zu können. Schließlich kann ich auf Anhieb mehrere Fehler nennen, die Compiler hier anmerken würde, schlicht deshalb, weil das Beispiel unvollständig ist. Im Ergebnis schaue ich mir den Code so gar nicht an.
Im Übrigen ist BaseChnA::getConcreteMember ein Template, bei dem der jeweilige Templateparameter nicht deduziert werden kann und folglich explizit angegeben werden muss.
-
camper schrieb:
In solchen Fällen sollte auch der gepostete Code in (ansonsten) compilierbaren Zustand sein, um den Fehler eindeutig identifizieren zu können. Schließlich kann ich auf Anhieb mehrere Fehler nennen, die Compiler hier anmerken würde, schlicht deshalb, weil das Beispiel unvollständig ist. Im Ergebnis schaue ich mir den Code so gar nicht an.
Ich dachte dass man an meinem Bsp mit den relevanten Code-Bestandteilen einen prinzipiellen Fehler erkennen kann und dass der komplette Code (umfasst ja immerhin 6 Klassen) die Sache in diesem Fall schwieriger gestaltet.
camper schrieb:
Im Übrigen ist BaseChnA::getConcreteMember ein Template, bei dem der jeweilige Templateparameter nicht deduziert werden kann und folglich explizit angegeben werden muss.
Okay, das hab ich jetzt nicht ganz verstanden. Heißt das, dass der tatsächlich zurückzugebende Typ der Funktion bereits beim Aufruf bekannt sein muss, also bspw. ein Objekt des selben Typs als Parameter übergeben werden müsste?
-
getConcreteMember<ConcreteMember1>()->doSthSpecial1();
-
Ja genau, oder soll der Compiler raten?
-
Radix schrieb:
der komplette Code (umfasst ja immerhin 6 Klassen)
Das ist aber nicht sooo viel, und sollte kein Hinderungsgrund sein, dein Design nochmal zu überdenken. Denn wenn du für jedes neue Feature, das sich durch besseres Design schön einfügen ließe einen weiteren Hack einbauen musst, hast du demnächst absolut unwartbaren Code, der sowieso neu designed werden muss, und dann dauerts richtig lange!
-
lego_123 schrieb:
Radix schrieb:
der komplette Code (umfasst ja immerhin 6 Klassen)
Das ist aber nicht sooo viel, und sollte kein Hinderungsgrund sein, dein Design nochmal zu überdenken. Denn wenn du für jedes neue Feature, das sich durch besseres Design schön einfügen ließe einen weiteren Hack einbauen musst, hast du demnächst absolut unwartbaren Code, der sowieso neu designed werden muss, und dann dauerts richtig lange!
Mit den 6 Klassen meinte ich nur meinen Testcode, das richtige Programm hat 'ne andere Größenordnung...
Th69 schrieb:
Ja genau, oder soll der Compiler raten?
Ich hab irgendwie damit gerechnet dass das zur Laufzeit bewerkstelligt werden kann. Okay, ist bei Template-Funktionen also nicht der Fall und die Lösung muss damit anders aussehen.
Ich müsste bspw. die Fallunterscheidung - falls eine nötig ist (und das ist glücklicherweise nicht bei vielen Channel-Klassen der Fall) - in die Channel-Klasse verlegen.
-
Radix schrieb:
Th69 schrieb:
Ja genau, oder soll der Compiler raten?
Ich hab irgendwie damit gerechnet dass das zur Laufzeit bewerkstelligt werden kann.
Template != Runtime!!!
Templates werden zur Compiletime ausgewertet und in Code gegossen. Jede Template-Funktion/Klasse bekommt für eine andere Zusammensetzung der template-Parameter eigenen Code generiert und kompiliert.