2010-07-12 57 views
3

因为我喜欢用C#和C++编程,所以我正在实现一个C#类事件系统作为我的计划C++ SFML的坚实基础-GUI。std :: tr1 :: function :: target <TFuncPtr> and co-/ contravariance

这只是我的代码的摘录,我希望这个澄清我的概念:

// Event.h 
// STL headers: 
#include <functional> 
#include <type_traits> 
#include <iostream> 
// boost headers: 
#include <boost/signals/trackable.hpp> 
#include <boost/signal.hpp> 

namespace Utils 
{ 
    namespace Gui 
    { 
     #define IMPLEMENTS_EVENT(EVENTNAME, EVENTARGS) public: \ 
      Utils::Gui::IEvent<EVENTARGS>& EVENTNAME() { return m_on##EVENTNAME; } \ 
     protected: \ 
      virtual void On##EVENTNAME(EVENTARGS& e) { m_on##EVENTNAME(this, e); } \ 
     private: \ 
      Utils::Gui::Event<EVENTARGS> m_on##EVENTNAME; 


     #define MAKE_EVENTFIRING_CLASS(EVENTNAME, EVENTARGS) class Fires##EVENTNAME##Event \ 
     { \ 
      IMPLEMENTS_EVENT(EVENTNAME, EVENTARGS); \ 
     }; 


     class EventArgs 
     { 
     public: 
      static EventArgs Empty; 
     }; 

     EventArgs EventArgs::Empty = EventArgs(); 

     template<class TEventArgs> 
     class EventHandler : public std::function<void (void*, TEventArgs&)> 
     { 
      static_assert(std::is_base_of<EventArgs, TEventArgs>::value, 
       "EventHandler must be instantiated with a TEventArgs template paramater type deriving from EventArgs."); 
     public: 
      typedef void Signature(void*, TEventArgs&); 
      typedef void (*HandlerPtr)(void*, TEventArgs&); 

      EventHandler() : std::function<Signature>() { } 

      template<class TContravariantEventArgs> 
      EventHandler(const EventHandler<TContravariantEventArgs>& rhs) 
       : std::function<Signature>(reinterpret_cast<HandlerPtr>(*rhs.target<EventHandler<TContravariantEventArgs>::HandlerPtr>())) 
      { 
       static_assert(std::is_base_of<TContravariantEventArgs, TEventArgs>::value, 
        "The eventHandler instance to copy does not suffice the rules of contravariance."); 
      } 

      template<class F> 
      EventHandler(F f) : std::function<Signature>(f) { } 

      template<class F, class Allocator> 
      EventHandler(F f, Allocator alloc) : std::function<Signature>(f, alloc) { } 
     }; 

     template<class TEventArgs> 
     class IEvent 
     { 
     public: 
      typedef boost::signal<void (void*, TEventArgs&)> SignalType; 

      void operator+= (const EventHandler<TEventArgs>& eventHandler) 
      { 
       Subscribe(eventHandler); 
      } 

      void operator-= (const EventHandler<TEventArgs>& eventHandler) 
      { 
       Unsubscribe(eventHandler); 
      } 

      virtual void Subscribe(const EventHandler<TEventArgs>& eventHandler) = 0; 

      virtual void Subscribe(const EventHandler<TEventArgs>& eventHandler, int group) = 0; 

      virtual void Unsubscribe(const EventHandler<TEventArgs>& eventHandler) = 0; 
     }; 

     template<class TEventArgs> 
     class Event : public IEvent<TEventArgs> 
     { 
     public: 
      virtual void Subscribe(const EventHandler<TEventArgs>& eventHandler) 
      { 
       m_signal.connect(*eventHandler.target<EventHandler<TEventArgs>::HandlerPtr>()); 
      } 

      virtual void Subscribe(const EventHandler<TEventArgs>& eventHandler, int group) 
      { 
       m_signal.connect(group, *eventHandler.target<EventHandler<TEventArgs>::HandlerPtr>()); 
      } 

      virtual void Unsubscribe(const EventHandler<TEventArgs>& eventHandler) 
      { 
       m_signal.disconnect(*eventHandler.target<EventHandler<TEventArgs>::HandlerPtr>()); 
      } 

      void operator() (void* sender, TEventArgs& e) 
      { 
       m_signal(sender, e); 
      } 

     private: 
      SignalType m_signal; 
     }; 

     class IEventListener : public boost::signals::trackable 
     { 
     }; 
    }; 
}; 

正如你所看到的,我使用boost ::信号作为我的实际事件系统,但我将其封装与IEvent接口(实际上是一个抽象类),以防止事件侦听器通过operator()触发事件。

为了方便起见,我重载了加法赋值和减法赋值运算符。如果我现在从IEventListener派生出我的事件监听类,那么我可以编写代码而不必担心信号中的悬挂函数指针。

到目前为止,我测试我的结果,但我有麻烦std::tr1::function::target<TFuncPtr>()

class BaseEventArgs : public Utils::Gui::EventArgs 
{ 
}; 

class DerivedEventArgs : public BaseEventArgs 
{ 
}; 

void Event_BaseEventRaised(void* sender, BaseEventArgs& e) 
{ 
    std::cout << "Event_BaseEventRaised called"; 
} 

void Event_DerivedEventRaised(void* sender, DerivedEventArgs& e) 
{ 
    std::cout << "Event_DerivedEventRaised called"; 
} 

int main() 
{ 
    using namespace Utils::Gui; 
    typedef EventHandler<BaseEventArgs>::HandlerPtr pfnBaseEventHandler; 
    typedef EventHandler<DerivedEventArgs>::HandlerPtr pfnNewEventHandler; 

    // BaseEventHandler with a function taking a BaseEventArgs 
    EventHandler<BaseEventArgs> baseEventHandler(Event_BaseEventRaised); 
    // DerivedEventHandler with a function taking a DerivedEventArgs 
    EventHandler<DerivedEventArgs> newEventHandler(Event_DerivedEventRaised); 
    // DerivedEventHandler with a function taking a BaseEventArgs -> Covariance 
    EventHandler<DerivedEventArgs> covariantBaseEventHandler(Event_BaseEventRaised); 

    const pfnBaseEventHandler* pBaseFunc = baseEventHandler.target<pfnBaseEventHandler>(); 
    std::cout << "baseEventHandler function pointer is " << ((pBaseFunc != nullptr) ? "valid" : "invalid") << std::endl; 

    const pfnNewEventHandler* pNewFunc = newEventHandler.target<pfnNewEventHandler>(); 
    std::cout << "baseEventHandler function pointer is " << ((pNewFunc != nullptr) ? "valid" : "invalid") << std::endl; 

    // Here is the error, covariantBaseEventHandler actually stores a pfnBaseEventHandler: 
    pNewFunc = covariantBaseEventHandler.target<pfnNewEventHandler>(); 
    std::cout << "covariantBaseEventHandler as pfnNewEventHandler function pointer is " << ((pNewFunc != nullptr) ? "valid" : "invalid") << std::endl; 

    // This works as expected, but template forces compile-time knowledge of the function pointer type 
    pBaseFunc = covariantBaseEventHandler.target<pfnBaseEventHandler>(); 
    std::cout << "covariantBaseEventHandler as pfnBaseEventHandler function pointer is " << ((pBaseFunc != nullptr) ? "valid" : "invalid") << std::endl; 

    return EXIT_SUCCESS; 
} 

EventHandler<TEventArgs>::target<TFuncPtr>()方法只会返回一个有效的指针,如果TFuncPtr是存储在仿函数类型完全相同的,无论协方差。 由于RTTI检查,它禁止访问指针作为一个标准的弱类型C函数指针,这是一种恼人的情况下,像这样的一种。

EventHandler属于DerivedEventArgs类型,但仍指向pfnBaseEventHandler函数,即使该函数是通过构造函数运行的。

这意味着,std :: tr1 ::函数本身“支持”反转,但我找不到一种简单的从std :: tr1 :: funcion对象中获取函数指针的方法, t在编译时知道它的类型,这是模板参数所需的。

我希望在像这样的情况下,他们添加了一个像RAII指针类型一样的简单get()方法。我想知道是否有办法解决这个问题,最好是在编译时通过模板(我认为这是唯一的方法)。

+0

要格式化代码,请选择并点击文本输入区域上方的1010按钮 - 不要使用HTML预编码和/或代码标签。 – 2010-07-12 11:17:37

+0

@ Sebastion:使用编辑窗口顶部的小101010按钮格式化代码。 (并且您阅读了编辑窗口右侧的帮助以获得帮助。)我进入并格式化了您的代码。 – sbi 2010-07-12 11:17:39

+0

是的,我阅读了这个缩进的东西并进行了测试,但由于预览没有立即格式化代码,我使用HTML标签。现在我肯定更聪明。感谢你们三个整理我的东西。 @Roger Pate:是的,这就是我所怀疑的......我现在要去尝试设置一个简短的例子。 – 2010-07-12 11:55:00

回答

1

刚发现问题的解决方案。看起来我只是错过了在不同位置演员阵容:

template<class TEventArgs> 
class EventHandler : public std::function<void (void*, TEventArgs&)> 
{ 
public: 
    typedef void Signature(void*, TEventArgs&); 
    typedef void (*HandlerPtr)(void*, TEventArgs&); 

    // ... 

    template<class TContravariantEventArgs> 
    EventHandler(const EventHandler<TContravariantEventArgs>& rhs) 
     : std::function<Signature>(reinterpret_cast<HandlerPtr>(*rhs.target<EventHandler<TContravariantEventArgs>::HandlerPtr>())) 
    { 
     static_assert(std::is_base_of<TContravariantEventArgs, TEventArgs>::value, 
      "The eventHandler instance to copy does not suffice the rules of contravariance."); 
    } 

    // ... 
} 

这是如何工作的。谢谢你,让我顺利介绍这个真棒社区!

相关问题