VS2010 Bug?



  • Hallo,

    folgender Code bereitet mir in VS2010 Probleme:

    template <typename Type, typename Param>
    class EventHandler
    {
    private:
    	class Handler
    	{
    	public:
    		typedef void (Handler::*Type)(Param);
    
    		Handler *source;
    		Type function;
    	};
    
    public:
    	template <typename T>
    	void Add(void *source, T function)
    	{
    		Handler h;
    		h.source = reinterpret_cast<Handler*>(source);
    		h.function = reinterpret_cast<Handler::Type>(function);
    		...
    	}
    
    	...
    };
    
    class Test : std::enable_shared_from_this<Test>
    {
    public:
    	EventHandler<void(const std::shared_ptr<Test> &), const
    	std::shared_ptr<Test> &> e;
    
    	Test()
    	{
    		e.Add(this, &Test::func);
    	}
    	virtual ~Test() { }
    
    	void func(const std::shared_ptr<Test> &p) { }
    };
    

    Fehlermeldung:

    Error 1 error C2440: 'reinterpret_cast' : cannot convert from 'void (__thiscall Test::* )(const std::tr1::shared_ptr<_Ty> &)' to 'void (__thiscall EventHandler<Type,Param>::Handler::* )(Param)'
    

    Problem lässt sich lösen, wenn man entweder die Klasse Test nicht virtual macht oder std::enable_shared_from_this<Test> weglässt.

    In ideone kompiliert der Code ohne Fehler (http://ideone.com/WG7f8).

    Bug in VS2010 oder ideone?

    greetz KN4CK3R



  • Reinterpret_cast macht an der Stelle mit Sicherheit nicht das, was du erreichen willst.
    Warum willst du ein void* übergeben und irgendein T, damti verlierst du wertvolle Typinformationen. z.B. würde folgendes "gehen":

    int i;
    eventHandler.Add(&i, i);
    

    Was willst du erreichen?



  • mit Add lassen sich Funktionen einer Klasse dem EventHandler zuweisen. Per Invoke können diese dann von einer anderen Stelle aufgerufen werden.

    void Invoke(Param param)
    {
    	for (auto it = handlers.begin(); it != handlers.end(); it++)
    	{
    		Handler &handler = *it;
    		(handler.source->*handler.function)(param);
    	}
    }
    

    Also verschiedene Funktionen registrieren und dann per Invoke alle nacheinander aufrufen.

    Test t;
    t.e.Invoke(0); //ruft Test::func(0) auf
    

    greetz KN4CK3R



  • MSVC 2010 kennt da schon schöne und nützliche Features des C++0x Standard: std::function und Lambdas. Damit sieht dein Code wie folgt aus:

    template <typename Signature>
    class EventHandler
    {
        typedef std::function<Signature> Handler;
        std::vector<Handler> handlers;
    public:
        void Add(Handler const& h)
        {
             handlers.push_back(h);
        }
    
        template <class T>
        void invoke(T&& param)
        {
            for (auto it = handlers.begin(); it != handlers.end(); ++it)
            {
                 Handler& h = *it;
                 h(std::forward<T>(param));
            }
        }
    };
    
    class Test : std::enable_shared_from_this<Test>
    {
    public:
        EventHandler<void(const std::shared_ptr<Test> &p)> e;
    
        Test()
        {
            e.Add([this](const std::shared_ptr<Test> &p)
            {
                 func(p);
            });
            //alternativ:  
            // e.Add(std::bind(&Test::func, this, std::placeholders::_1));
        }
        virtual ~Test() { }
    
        void func(const std::shared_ptr<Test> &p) { }
    };
    


  • Irgendwie schein Laufzeitpolymorphie durch Vererbung und virtuelle Funktionen aus der Mode zu kommen.



  • @pumuckl: Tatsache, machts einfacher und funktioniert.

    @knivil: inwiefern?

    greetz KN4CK3R


Anmelden zum Antworten