Template compiler problem
-
Hallo,
beim spielen mit Templates bin ich auf ein merkwürdiges Problem gestoßen, was ich mir nicht erklären kann.
Unter VS 2008, also kein C++11 bekomme ich folgende Fehlermeldung:
1>d:\temp\test\templatetest\templatetest.cpp(41) : error C2784: 'TType *GetFromElementManager(Predicate<TType>)' : could not deduce template argument for 'Predicate<TType>' from 'SpecificPredicate'
1> d:\temp\test\templatetest\templatetest.cpp(18) : see declaration of 'GetFromElementManager'
1>d:\temp\test\templatetest\templatetest.cpp(41) : error C2893: Failed to specialize function template 'TType *GetFromElementManager(Predicate<TType>)'
1> With the following template arguments:
1> 'std::string'Der Beispielcode ist hier:
#include <string> template<typename TType> class Predicate { public: virtual ~Predicate(){}; virtual bool Match(TType &match) const = 0; }; template <typename TType> TType * GetFromElementManager(Predicate<TType> predicate) { // Dummy test TType * t = new TType(); if(predicate.Match(*t)) { return t; } return NULL; } class SpecificPredicate : Predicate<std::string> { virtual bool Match(std::string &match) const{ return false;} }; int main(int argc,char* argv[]) { SpecificPredicate sp; GetFromElementManager(sp); return 0; }Was ich damit erreichen wollte ist eine generische Methode GetFromElementManager die Typunabhängig ein Objekt erstellt und auf dieses ein Predicate anwendet. Wenn das Predikat true ist, wird das Objekt zurückgegeben.
Der Code oben ist nur noch der minimale Reprocase, im richtigen Code hole ich mir TType im GetFromElementManager wo anders her.
Aber ich verstehe die Meldung nicht.
Wenn ich explizit
GetFromElementManager<std::string>(sp);schreibe, bekomme ich
1>d:\temp\test\templatetest\templatetest.cpp(41) : error C2770: invalid explicit template argument(s) for 'TType *GetFromElementManager(Predicate<TType>)'
1> d:\temp\test\templatetest\templatetest.cpp(18) : see declaration of 'GetFromElementManager'
-
Bringt es etwas, "public" abzuleiten, sodass der Specific-Typ da konvertierbar in das Predicate ist?
-
Abstrakte Klassen können keine Funktionsargumente sein, der Compiler hat recht. Die Fehlermeldung ist allerdings wenig brauchbar.
Grundsätzlich kann es 3 Gründe geben, weshalb Argumentdeduktion fehlschlägt:
1. Für mindestens ein Templateargument existiert kein Parameter, aus dem dieses deduziert werden kann (solche Templates benötigen immer eine explizite ANgabe des Templateparameters), oder
2. Ein Templateargument kann aus mehreren Argumenten deduziert werden, aber mit unterschiedlichem Ergebnis, oder
3. Die Templateargumente können deduziert werden, die sich ergebende Funktionssignatur ist aber ungültig.
Hier liegt der 3. Fall vor. Dass die Ableitung nat. public sein müsste, damit der Aufruf stattfinden könnte (wenn wir unterstellen, die Basisklasse wäre nicht abstrakt), hat keinen Einfluss auf die Argumentdeduktion.
-
Mal davon ab, dass ich die Begründung nicht so treffend hätte formulieren können, würde ich das Argument einfach weglassen und den Typ als Template-Parameter angeben, der nicht deduziert werden kann, sodass man ihn in beim Funktionsaufruf als Template-Parameter mitgeben muss. In diesem Fall ist da echt keine Art "tag"-Argument nötig.
-
Auch ohne die Abstrakt- und private-Problematik würde hier ja Slicing eintreten. Das Prädikat wird also sinnvollerweise sowieso per Referenz übergeben - und dann sollte es auch keine Probleme bereiten.
-
Wenn ich Predicate nicht abstrakt mache, kompiliert es in der Tat.
Predicate wurde in der Anwendung auch als const & übergeben. Das ist nur beim experimentieren wohl hinten runter gefallen.
Danke für die Hilfe
-
Du erzeugst ein Speicherloch in
GetFromElementManager, wenntnicht durch das Prädikat akzeptiert wird.
-
Jepp, danke für den Hinweis.
Im richtigen Code wird eine Liste vorhandener Objekte durchlaufen.