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





  • 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


Anmelden zum Antworten