Austauschbarer Funktor als (Default-)Argument in Memberfunktion
-
Hallo alle.
Ich versuche eine Struktur zu programmieren, die Lösungsvorschläge für ein mathematisches Problem (hier Graph Coloring) verwaltet. Die Grundidee ist, dass ein Lösungsvorschlag (gcSolution) nur dann gespeichert wird, wenn er sowohl gewisse Randbedingungen (gcConstraints) erfüllt als auch es nicht schon einen Lösungsvorschlag gibt, der in allen Hinsichten besser ist. Was genau jetzt aber "besser" heisst, möchte ich später bestimmen können, also benutze ich dafür einen Funktor (so dass ich ggf. später da schnell einen neuen schreiben kann). Zum Beispiel den einfachen hier (wenn eine Lösung weniger Konflikte verursacht als eine andere, ist sie besser):
//Funktor struct orderByLeastConflictsLIST{ bool operator()(const gcSolution& s1, const gcSolution& s2){ return(s1.numberConflicts < s2.numberConflicts); } };Der Funktor an sich funktioniert prima, auch schon erfolgreich benutzt um Listen von Lösungsvorschlägen mit list::sort() zu sortieren.
Mein Problem ist jetzt, dass der Linker meine Aussortierfunktion für schlechte Lösungen in der Randbedingungsklasse nicht frisst, und ich bin nicht sicher, woran es liegt. Diese Aussortierfunktion hat einen Funktor als Templateparameter (den ich in einem zweiten Schritt übrigens gern defaulten würde, habs rausgenommen weil ich dachte, das würde mein Problem verursachen):
class gcConstraints{ public: //... template<typename solutionSuperiorCriterion> bool addAcceptableSolution(const gcSolution& s, const vector<unsigned>& initialColoring, list<gcSolution>& currentSolutionList, solutionSuperiorCriterion crit)const; //... }Hier die Implementation in der zugehörigen .cpp file:
template<typename solutionSuperiorCriterion> bool gcConstraints::addAcceptableSolution(const gcSolution& candidate, const vector<unsigned>& initialColoring, list<gcSolution>& currentSolutionList, solutionSuperiorCriterion super)const{ //... }Lässt sich kompilieren, wenn ich dann aber in der main() die entsprechende Funktion aufrufen möchte:
gcConstraints theConstraints( (...Parameter...) ); theConstraints.addAcceptableSolution(temp, dummy, theList, orderByLeastConflictsLIST() ) );bekomme ich einen Linker error (Dev-CPP mit MinGW):
[Linker error] undefined reference to `bool gcConstraints::addAcceptableSolution<orderByLeastConflictsLIST>(gcSolution const&, std::vector<unsigned int, std::allocator<unsigned int> > const&, std::list<gcSolution, std::allocator<gcSolution> >&, orderByLeastConflictsLIST) const'Ich schätze ich hab irgendwie mit den templates Mist gebaut, aber ich seh nicht, wo. Hat jemand eine Idee?
Danke!
-
Bitte lies in irgendeiner C++ FAQ nach, das ist so ein Standardfehler.
Oh Mann...Pack die Implementierung des Templates mit ins Header File.
-
*gegen Kopf hau*
Sorry. Eigentlich sollte ich das selbst wissen, schon dreimal falsch und zehnmal richtig gemacht, aber ich dachte es wär was komplizierteres.
Daniel
-
Hihi, OK.
Bloss komisch dass dir das beim Schreiben dieser Frage nicht aufgefallen ist. Aber manchmal steht man halt im Finstern, ich kenne das wohl
-
Um aber gerade nochmal auf den Default-Teil zurückzukommen:
template<typename solutionSuperiorCriterion> bool addAcceptableSolution(const gcSolution& s, const vector<unsigned>& initialColoring, list<gcSolution>& currentSolutionList, solutionSuperiorCriterion crit = completelySuperior() )const;mit zugehöriger Implementierung in der selben Datei (jaja) lässt sich kompilieren, falls diese Funktion aber in der main() ohne das letzte (Default-)Argument aufgerufen wird, krieg ich vom compiler ein "no matching function for call". Der Funktor completelySuperior() ist korrekt definiert und included.
Womit hängt das zusammen, bzw. was muss ich machen, damit ich einen bestimmten Funktor als Defaultargument benutzen kann (a la STL)?
Danke!
-
Das Problem ist folgendes: wenn du den letzten Parameter nicht angibst, kann der Compiler das Template-Argument nicht herleiten. Folgende zwei Möglichkeiten fallen mir ein:
a) Übergebe zusätzlich ein default-Templateparameter (den Typ von deinem default-Functor)
b) Lass den Default-Parameter weg und überlade die Funktion mit einer zweiten, die kein Template ist und kein Functor-Parameter ist. Die ruft dann lediglich das Template mit dem zusätzlichen Parameter auf.
-
Ah, verstehe. Danke für den Hinweis!