Ambiguous call bei Funktionstemplate Deklaration + Definition


  • Administrator

    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


  • Administrator

    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)
    

  • Administrator

    @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 ­čśë


  • Administrator

    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


  • Administrator

    Hmmm, das macht keinen Sinn ­čÖé

    Wenn ich das template<typename ObjectT> wegnehme und alle ObjectT 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 Zeilen

    int (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.


  • Administrator

    @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 nicht ­čÖé

    Das 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 das ID_FUNC und HOUSE_ID_FUNC rausnehmen und die beiden Funktionen get_id und get_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.html

    http://blogs.msdn.com/astebner/archive/2005/08/13/451338.aspx



  • Also Bugs f├╝r VS reporten is ganz einfach.
    Geh auf

    https://connect.microsoft.com/

    Mach dir nen Account, mach eine "Connection" zu "Visual Studio and .NET Framework", und reporte den Bug. Wirklich nicht schwer.


  • Administrator

    hustbaer schrieb:

    Also Bugs f├╝r VS reporten is ganz einfach.
    Geh auf

    https://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


Log in to reply