Verflixter Template-Fehler?
-
Hallo!
ich will mal einen ganz primitiven Binärbaum programmieren. Gleichzeitig würde ich gerne ein wenig C++0x machen ---> benutze als IDE Visual Studio 2010 Beta 1.Beim kompilieren bekommen ich folgenden Fehler:
term does not evaluate to a function taking 2 arguments [...]xxcallobjUnd da ist der Hund begraben: der Fehlercode in irgend einer Standard-Datei. Das stand in der Fehlerausgabe:
c:\programme\microsoft visual studio 10.0\vc\include\xxfunction(226) : see reference to function template instantiation 'void std::tr1::_Function_impl2<_Ret,_Arg0,_Arg1>::_Reset0o<_Myimpl,_Fty,std::allocator<_Ty>>(_Fty,_Alloc)' being compiled 1> with 1> [ 1> _Ret=bool, 1> _Arg0=const std::basic_string<char,std::char_traits<char>,std::allocator<char>> &, 1> _Arg1=const std::basic_string<char,std::char_traits<char>,std::allocator<char>> &, 1> _Fty=std::pair<std::string,int>, 1> _Ty=std::tr1::_Function_impl2<bool,const std::basic_string<char,std::char_traits<char>,std::allocator<char>> &,const std::basic_string<char,std::char_traits<char>,std::allocator<char>> &>, 1> _Alloc=std::allocator<std::tr1::_Function_impl2<bool,const std::basic_string<char,std::char_traits<char>,std::allocator<char>> &,const std::basic_string<char,std::char_traits<char>,std::allocator<char>> &>> 1> ] 1> c:\dokumente und einstellungen\ad acta\desktop\c++\algorythm\algorythm\node.hpp(55) : see reference to function template instantiation 'std::tr1::function<_Fty>::function<K>(_Fx)' being compiled 1> with 1> [ 1> _Fty=bool (const std::string &,const std::string &), 1> K=std::pair<std::string,int>, 1> _Fx=std::pair<std::string,int> 1> ] 1> c:\dokumente und einstellungen\ad acta\desktop\c++\algorythm\algorythm\node.hpp(47) : while compiling class template member function 'std::pair<_Ty1,_Ty2> node<key_type,value_type,struct_type>::insert(const struct_type &)' 1> with 1> [ 1> _Ty1=const int *, 1> _Ty2=bool, 1> key_type=std::string, 1> value_type=int, 1> struct_type=std::pair<std::string,int> 1> ] 1> c:\dokumente und einstellungen\ad acta\desktop\c++\algorythm\algorythm\tree.hpp(27) : see reference to class template instantiation 'node<key_type,value_type,struct_type>' being compiled 1> with 1> [ 1> key_type=std::string, 1> value_type=int, 1> struct_type=std::pair<std::string,int> 1> ] 1> c:\dokumente und einstellungen\ad acta\desktop\c++\algorythm\algorythm\tree.hpp(26) : while compiling class template member function 'tree<key_type,value_type>::tree(std::tr1::function<_Fty> &&)' 1> with 1> [ 1> key_type=std::string, 1> value_type=int, 1> _Fty=bool (const std::string &,const std::string &) 1> ] 1> c:\dokumente und einstellungen\ad acta\desktop\c++\algorythm\algorythm\main.cpp(16) : see reference to class template instantiation 'tree<key_type,value_type>' being compiled 1> with 1> [ 1> key_type=std::string, 1> value_type=int 1> ]blabla usw.
Scheinbar passt dem Compiler irgendwas nicht an meiner Anwendung von std::function, oder?
Das kommt so in meinem Code vor:// main.cpp: // Anbei, ein Tree mit String als Schlüssel und int als Speicherwert // das Lambda soll eine Vergleichsfunktion für Strings sein tree<string, int> t1([&](const string s1, const string s2) -> bool { unsigned short min_len = (s1.length() > s2.length()) ? s2.length() : s1.length(); for(size_t i = 0; i < min_len; i++) { if(s1[i] > s2[i]) return true; else if(s1[i] < s2[i]) return false; } }); // den speichere ich in Tree so ab: typedef std::function<bool (const key_type&, const key_type&)> comp_fun; comp_fun compare; // C-tor von tree, Übergabe als Rvalue ok? template <typename T, typename U, typename K> tree<T, U, K>::tree(comp_fun &&cmp) : compare(cmp) { root = new node<T, U, K>(cmp); } // C-tor von node template <typename T, typename U, typename K> node<T, U, K>::node(comp_fun cmp) : compare(cmp) { } // Anwendungsversuch beim Einfügen in den Baum if(compare(val_rep.first, s.first)) { // rufe es als Funktion auf if(bough.first == 0) { bough.first = new node<T, U, K>(s); return std::pair<const U*, bool>(&(s.second), true); } else { return bough.first->insert(s); } }Das ist alles verdammt verflixt. Weiß jemand, wie ich das irgendwie aufrollen und lösen kann?
-
STLFilt könnte dir das Leben vielleicht bissl einfacher machen.
-
Hier ein paar Kommentare zum Stil:
Warum schreibst Du eine Tree-Klasse, wenn Du std::map benutzen kannst?
Warum legst Du Dich eigentlich auf std::function fest? Du kannst den Typ des Komparators doch genauso als Template-Parameter einführen. Du kannst dann ja immer noch std::function<> als Template-Parameter benutzen und dem Konstructor ein Lambda-Objekt übergeben. std::less als Default ist einfach extrem praktisch.
typedef map<string,dings, function<bool(string const&, string const&)> > map_type; map_type meine_map ( [](string const& a, string const& b) { return a < b; } );Wenn Dein Compiler auch schon "template typedefs" unterstützt kannst Du ja auch das schreiben:
template<typename Key, typename Mapped> using map_polycmp = std::map<Key,Mapped,std::function<bool(Key const&,Key const&)>>; ... map_polycmp<string,dings> meine_map ( [](string const&a, string const&b) { return a<b; } );Man beachte auch, dass die "capture-clause" leer ([] statt [&]) ist. Es wird keine Refenz auf den umliegenden scope benötigt.
Die Übergabe des Komparators ("comp_t && comp") ist unpraktisch. Du kannst so ja nur Rvalues entgegennehmen und keine Lvalues (!). Du bräuchtest also noch einen comp_t const& overload. Wenn Du aber einen halbwegs brauchbaren Compiler hast, kannst Du auch einfach pass-by-value benutzen, ohne dass die Performanz auch nur ein bischen leidet. Der Compiler sollte hier bei Übergabe eines Lambda-Objektes fähig sein, eine "copy elision" durchzuführen. Damit kannst Du Dir die &&/const&-overload Geschichte sparen. Benutze aber reichlich
std::movestattdessen:// C-tor von tree template <typename T, typename U, typename K> tree<T, U, K>::tree(comp_fun cmp) : compare( std::move(cmp) ) // cmp wird ja nicht mehr benötigt. { root = 0; // Ein "leerer Baum", sollte ohne new auskommen! }Es sieht auch so aus, als ob alle Deine Knoten jeweils eine Kopie des Komparators speichern. Das ist nicht nötig und kann sehr teuer werden, wenn der Comparator "unhandlich" ist. Wenn Du std::function-Ojekte kopierst und für das Funktion-Objekt keine "small function optimization" durchgeführt wird, wird für die neue Kopie der Freispeicher beantsprucht.
Sonst: Versuch mal den Fehler zu isolieren.
BTW: Im Englischen heißt das "algorithm", also ohne y
Gruß,
SP
-
Herzlichen Dank für deine Kritik.
Ich werde mal schauen, dass ich den Lambda-Functor zum Vergleichen in die Tpl-Liste übergebe.
Mit der Template-Übergabe müsste ja dann auch das Problem der vielen Kopien des Compare-Functos erledigt sein. Den Fehler habe ich in den const-Wursteleien gefunden. Ich habe jetzt beim insert() die const in den call-by-references entfernt, die Elemente werden eh nicht verändert und für diese Garantie kann man als Template-Parameter ja auch einen konstanten Typ angeben. Es war also irgendsowas wie ein Konvertierungsproblem in einem Konstruktor durch const.