Ambiguous call bei Funktionstemplate Deklaration + Definition
-
Vielleicht sieht einer von euch, wieso der Kompiler mir hier ein "Ambiguous Call" an den Kopf wirft. Ich geh gleich essen und habe aktuell nicht die leiseste Ahnung, wieso der Fehler kommt
namespace mll { // ... namespace manager { // ... template<typename ObjectT> std::pair < typename ObjectManager<ObjectT>::HouseIterator, typename ObjectManager<ObjectT>::HouseIterator > get_house_range(ObjectID houseID); } } // mll::manager ////////////////////////////////////////////////////////////////////////// // Templates implementation namespace mll { // ... namespace manager { // ... template<typename ObjectT> std::pair < typename ObjectManager<ObjectT>::HouseIterator, typename ObjectManager<ObjectT>::HouseIterator > get_house_range(ObjectID houseID) { mll::ObjectManager<ObjectT> const& m = mll::ObjectManager<ObjectT>::get_const_instance(); return m.get_house_range(houseID); } } } // mll::manager
// Irgendwo anders: mll::manager::get_house_range<mll::Flat>(0);
BUMM
1>c:\...\irgendwoanders.hpp(77) : error C2668: 'mll::manager::get_house_range' : ambiguous call to overloaded function 1> c:\...\objectmanager.hpp(380): could be 'std::pair<_Ty1,_Ty2> mll::manager::get_house_range<mll::Flat>(mll::ObjectID)' 1> with 1> [ 1> _Ty1=boost::multi_index::detail::bidir_node_iterator<boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<mll::Flat,std::allocator<mll::Flat>>>>, 1> _Ty2=boost::multi_index::detail::bidir_node_iterator<boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<mll::Flat,std::allocator<mll::Flat>>>> 1> ] 1> c:\...\objectmanager.hpp(128): or 'std::pair<_Ty1,_Ty2> mll::manager::get_house_range<mll::Flat>(mll::ObjectID)' 1> with 1> [ 1> _Ty1=boost::multi_index::detail::bidir_node_iterator<boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<mll::Flat,std::allocator<mll::Flat>>>>, 1> _Ty2=boost::multi_index::detail::bidir_node_iterator<boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<mll::Flat,std::allocator<mll::Flat>>>> 1> ] 1> while trying to match the argument list '(int)'
Was zum Geier überseh ich?Grüssli
-
Ok, hab mich voll gefressen, den Fehler finde ich immer noch nicht. Die Funktionsköpfe sind absolut identisch, nachgeprüft durch ein Copy&Paste. Bekomme aber immer noch den Fehler. Es sollte doch grundsätzlich eine Deklaration und Definition geben und nicht eine doppelte Definition ... Also nix mit "Ambiguous Call", zumindest in meiner Theorie
Wenn ich den Rückgabewert durch z.B.
void
ersetze, dann funktioniert es. Das wirft bei mir aber eher noch mehr Fragezeichen auf, als es Antworten bringt...Grüssli
-
Puh, kann grad nur raten weil kein Compiler zur hand ums zu überprüfen: versuch aus der Definition mal folgendes zu machen:
get_house_range<ObjectT>(ObjectID houseID)
-
@pumuckl,
Nein geht so nicht.Das Schlimme ist, ich kann den Fehler nicht mal reproduzieren mit anderem Code. Es geht nur mit meinem speziellen Code. Ich kriege nicht heraus, woran es liegt. *sich die Haare ausreisst*
Werde noch ein wenig weiter rumprobieren.
Grüssli
-
tja, mach ne neue Datei auf und copy&paste den Code stück für stück da rein und compilere - irgendwo auf dem Weg passierts dann
-
pumuckl schrieb:
tja, mach ne neue Datei auf und copy&paste den Code stück für stück da rein und compilere - irgendwo auf dem Weg passierts dann
Bleibt mir wohl nichts anderes übrig, aber das mach ich dann morgen. Irgendwie beschleicht mich aber so langsam das Gefühl, dass es nur ein Kompilerfehler ist. Ich hoffe es aber nicht, ich hoffe es ist wie immer nur ein Fehler des dummen Programmierers
Grüssli
-
Hmmm, das macht keinen Sinn
Wenn ich das
template<typename ObjectT>
wegnehme und alleObjectT
durch das Objekt direkt ersetze, gehts.
Es scheint zudem nur am Rückgabewert zu liegen, aber der kann ja kein "Ambiguous Call" auslösen.Ich habe den Code mal ein wenig zusammengefasst, so dass ihr, wenn ihr Lust dazu habt, den Fehler anschauen könnt. Es sind leider allerdings immer noch etwas mehr wie 300 Zeilen.
Verwendeter Kompiler ist der MSVC 2008.
Flat.hpp
////////////////////////////////////////////////////////////////////////// // Flat : Header file #ifndef MLL_H_FLAT_GUARD__ #define MLL_H_FLAT_GUARD__ //#include "ObjectID.hpp" typedef long ObjectID; namespace mll { ////////////////////////////////////////////////////////////////////////// // Flat class Flat { // Attributes // private: ObjectID m_id; ObjectID m_houseID; // Constructors & Destructor // public: Flat(ObjectID id, ObjectID houseID) : m_id(id) , m_houseID(houseID) {}; ~Flat(){}; // Methods // public: ObjectID get_id() const { return m_id; }; ObjectID get_house_id() const { return m_houseID; }; }; } // mll #endif // MLL_H_FLAT_GUARD__
ObjectManager.hpp
////////////////////////////////////////////////////////////////////////// // ObjectManager : Header file #ifndef MLL_H_OBJECT_MANAGER_GUARD__ #define MLL_H_OBJECT_MANAGER_GUARD__ //#include "ObjectID.hpp" typedef long ObjectID; #include <boost/serialization/singleton.hpp> #include <boost/multi_index/mem_fun.hpp> #include <boost/multi_index_container.hpp> #include <boost/multi_index/indexed_by.hpp> #include <boost/multi_index/ordered_index.hpp> #include <utility> namespace mll { ////////////////////////////////////////////////////////////////////////// // ObjectManager template < typename ObjectT, ObjectID (ObjectT::*ID_FUNC)() const = &ObjectT::get_id, ObjectID (ObjectT::*HOUSE_ID_FUNC)() const = &ObjectT::get_house_id > class ObjectManager : public boost::serialization::singleton<ObjectManager < ObjectT, ID_FUNC, HOUSE_ID_FUNC > > { // Typedefs // public: typedef ObjectT Object; private: typedef boost::multi_index_container < Object, boost::multi_index::indexed_by < boost::multi_index::ordered_unique < boost::multi_index::const_mem_fun < Object, ObjectID, ID_FUNC > >, boost::multi_index::ordered_non_unique < boost::multi_index::const_mem_fun < Object, ObjectID, HOUSE_ID_FUNC > > > > Container; public: typedef typename Container ::nth_index<1> ::type ::const_iterator HouseIterator; // Attributes // private: Container m_container; // Constructors & Destructor // public: ObjectManager(); // Methods // public: std::pair<HouseIterator, HouseIterator> get_house_range(ObjectID houseID) const; }; ////////////////////////////////////////////////////////////////////////// // Free functions namespace manager { template<typename ObjectT> std::pair < typename ObjectManager<ObjectT>::HouseIterator, typename ObjectManager<ObjectT>::HouseIterator > get_house_range(ObjectID houseID); } } // mll::manager ////////////////////////////////////////////////////////////////////////// // Templates implementation namespace mll { ////////////////////////////////////////////////////////////////////////// // ObjectManager /************************************************************************/ /* Constructors */ /************************************************************************/ template < typename ObjectT, ObjectID (ObjectT::*ID_FUNC)() const, ObjectID (ObjectT::*HOUSE_ID_FUNC)() const > ObjectManager < ObjectT, ID_FUNC, HOUSE_ID_FUNC > ::ObjectManager() : m_container() { } /************************************************************************/ /* Methods */ /************************************************************************/ template < typename ObjectT, ObjectID (ObjectT::*ID_FUNC)() const, ObjectID (ObjectT::*HOUSE_ID_FUNC)() const > std::pair < typename ObjectManager < ObjectT, ID_FUNC, HOUSE_ID_FUNC > ::HouseIterator, typename ObjectManager < ObjectT, ID_FUNC, HOUSE_ID_FUNC > ::HouseIterator > ObjectManager < ObjectT, ID_FUNC, HOUSE_ID_FUNC > ::get_house_range(ObjectID houseID) const { return m_container.get<1>().equal_range(houseID); } ////////////////////////////////////////////////////////////////////////// // Free functions namespace manager { template<typename ObjectT> std::pair < typename ObjectManager<ObjectT>::HouseIterator, typename ObjectManager<ObjectT>::HouseIterator > get_house_range(ObjectID houseID) { mll::ObjectManager<ObjectT> const& m = mll::ObjectManager<ObjectT>::get_const_instance(); return m.get_house_range(houseID); } } } // mll::manager #endif // MLL_H_OBJECT_MANAGER_GUARD__
main.cpp
////////////////////////////////////////////////////////////////////////// // main : Implementation file #include "Flat.hpp" #include "ObjectManager.hpp" int main() { mll::manager::get_house_range<mll::Flat>(0); return 0; }
Die einzige Lösung wäre aktuell ein Stilbruch. Müsste die Deklaration und Definition zusammenführen.
Grüssli
-
Hmm, ich habs mal probiert, und den Code einfach mal der Reihe nach in ein File kopiert. Aus Gründen (die mir ebenfalls nicht klar sind), hält der die Deklaration und die Definition für unterschiedliche Funktionen.
-
Weiß nicht, ob das den Fehler behebt, aber hier fehlt ein template:
return m_container.get<1>().equal_range(houseID); // should be -> return m_container.template get<1>().equal_range(houseID);
Wenn nach Zugriff auf einen Templatetyp auf ein weiteres Template zugegriffen wird, muss es mit template eingeleitet werden. Ansonsten wird das < als kleine-Op interpretiert.
Edit: Hier scheint auch eins zu fehlen:
typedef typename Container ::nth_index<1> ::type ::const_iterator HouseIterator; // should be -> typedef typename Container ::template nth_index<1> ::type ::const_iterator HouseIterator;
Kanns leider nicht compilieren, obs nun klappt, da ich seltsamerweise kein boost/serialization/singleton.hpp drauf habe.
-
Naja das lässt sich schon noch wesentlich weiter zusammenschrumpfen:
#include <vector> namespace mll { class foo { public: static const int CI = 123; int bar() const { return 0; } }; template < typename T, int (T::*ID_FUNC)() const = &T::bar, int QUUX = T::CI, int Z = 123 > class qux { public: typedef typename std::vector<T>::const_iterator iter; iter get2() const { return m_vec.begin(); } private: std::vector<T> m_vec; }; template<typename T> typename qux<T>::iter get(); template<typename T> typename qux<T>::iter get() { mll::qux<T> m; return m.get2(); } } ////////////////////////////////////////////////////////////////////////// int main() { mll::get<mll::foo>(); return 0; }
Scheint ein Compiler-Bug zu sein.
Wenn man die zwei Zeilenint (T::*ID_FUNC)() const = &T::bar, int QUUX = T::CI,
auskommentiert, dann geht's. Lässt man eine davon drinnen, geht's nichtmehr.
Wenn man beim Template Parameter QUUX den Default-Wert wegnimmt, und den Rest des Codes entsprechend anpasst, dann geht's. (Wenn man gleichzeitig die ID_FUNC Zeile auskommentiert, sonst natürlich nicht)
Wenn man dasselbe mit dem Template Parameter ID_FUNC versucht, geht es trotzdem nicht.
Irgendwo dürfte es da also 1) ein Problem mit Member-Function-Pointern als Template-Parameter geben. Und es dürfte 2) ein Problem mit Template-Parameter abhängigen Defaults für andere Template-Parameter geben.
@Dravere: Du übersiehst nichts, mach nen Bug-Report bei Microsoft!
p.S.: Workaround: lass die fwd-decl der Template-Funktion weg, und implementier sie gleich an Ort und Stelle.
-
@KasF,
Mit dem VC2008 nicht nötig. Sollte ich mir aber dringend angewöhnen, falls ich mal meinen Code mit einem anderen Kompiler kompilieren möchte@hustbaer,
Hab es mehrmals probiert soweit zu verkleinern, aber da funktionierte es bei mir immer. Aber dein Beispiel funktioniert einwandfrei nichtDas mit dem Zusammenführen von Deklaration und Definition habe ich ja bereits am Anfang hingeschrieben. Es wäre halt einfach ein Stilbruch und ich hasse Stilbrüche
Ich glaube ich werde eher dasID_FUNC
undHOUSE_ID_FUNC
rausnehmen und die beiden Funktionenget_id
undget_house_id
einfach voraussetzen. Die Wahrscheinlichkeit ist sowieso extrem gering, dass sich da ein paar Klassen anders verhalten werden. War mehr eine übermässige Vorsicht und Sicherheit.Den Bugreport würde ich ja gerne machen, wenn ich wüsste wo
Grüssli
-
Dravere schrieb:
Den Bugreport würde ich ja gerne machen, wenn ich wüsste wo :)Grüssli
Ein paar nette Erfahrungsberichte zum Thema:
http://weblog.timaltman.com/archive/2006/03/22/reporting-bugs-microsoft
http://www.oreillynet.com/mac/blog/2002/06/mission_impossible_submitting.htmlhttp://blogs.msdn.com/astebner/archive/2005/08/13/451338.aspx
-
Also Bugs für VS reporten is ganz einfach.
Geh aufhttps://connect.microsoft.com/
Mach dir nen Account, mach eine "Connection" zu "Visual Studio and .NET Framework", und reporte den Bug. Wirklich nicht schwer.
-
hustbaer schrieb:
Also Bugs für VS reporten is ganz einfach.
Geh aufhttps://connect.microsoft.com/
Mach dir nen Account, mach eine "Connection" zu "Visual Studio and .NET Framework", und reporte den Bug. Wirklich nicht schwer.
Abgesehen davon, dass man die Website kennen muss. Auf www.microsoft.com habe ich das irgendwie nicht gefunden.
Und was mir gar nicht gefällt ist, dass ich da einen Account machen muss. Wobei anscheinend mein MSN Account bereits ausreicht. Allerdings will Microsoft mehr Informationen, wenn ich da auf weiter drücke, passiert allerdings nichts. Wahrscheinlich wieder mal nur für den IE tauglich. Da habe ich keine Lust...Grüssli