我已经解决了我的问题。这是非常简洁的代码。信号也是一个模板类,它简单地定义了它可能发出的消息类型。因此,在将信号与槽连接时,Link 构造函数可以检查信号发出的消息类型与槽接受的消息类型的多态兼容性。然后无论是否需要动态转换,它都会复制适当的函数指针。此处未显示的是 Type 类以及如何使用它来检查消息类型的兼容性。
答案是如何定义这两个槽函数及其函数指针。
这是一个如何在类中定义插槽的示例:
class MyAction : public Action
{
public:
//! Define shared pointer on object
typedef std::shared_ptr<MyAction> Ptr;
//! Constructor
MyAction( const std::string& name )
: Action(name),
m_slotMsgM( this ),
m_slotMsgA( this ),
m_slotMsgB( this )
{
}
//! Register the slots with their name for dynamic linking
void configure()
{
add("processMsgM", &m_slotMsgM );
add("processMsgA", &m_slotMsgA );
add("processMsgB", &m_slotMsgB );
}
//! Slot method
void processMsgM( Message::Ptr msg, Link * link = nullptr )
{
cout << "MyAction::processMsgM: Msg " << msg->type().name() << endl;
}
//! Slot method
void processMsgA( MsgA::Ptr msg, Link * link = nullptr )
{
cout << "MyAction::processMsgA: Msg " << msg->type().name() << endl;
}
//! Slot method
void processMsgB( MsgB::Ptr msg, Link * link = nullptr )
{
cout << "MyAction::processMsgB: Msg " << msg->type().name() << endl;
}
protected:
//! Define slots
SlotT<MyAction, Message, &MyAction::processMsgM> m_slotMsgM;
SlotT<MyAction, MsgA, &MyAction::processMsgA> m_slotMsgA;
SlotT<MyAction, MsgB, &MyAction::processMsgB> m_slotMsgB;
};
这是 Slot 和 SlotT 类的定义。
class Link;
typedef std::set<Link*> LinkSet;
//! Base class for Slot template class
class Slot
{
friend class Link;
public:
//! Slot function pointer
typedef std::function<void ( Message::Ptr, Link* )> Function;
//! Disconnect all links
~Slot();
//! Return the type of message accepted by this Slot function
const TypeDef& messageType() const { return m_msgType; }
//! Return slot function applying a dynamic cast on the message pointer
Function getDynamicCastFunction() const
{ return m_dynamicCastFunction; }
//! Return slot function applying a static cast on the message pointer
Function getStaticCastFunction() const
{ return m_staticCastFunction; }
//! Operator () using the dynamic cast
void operator()(Message::Ptr msg, Link * link = nullptr )
{ m_dynamicCastFunction( msg, link); }
protected:
//! Construct Slot by derived class instance construction only
Slot( const TypeDef& type, Function dynamicCastFunction,
Function staticCastFunction ) :
m_msgType(type),
m_dynamicCastFunction(dynamicCastFunction),
m_staticCastFunction(staticCastFunction)
{
}
//! Insert link in set
void connect( Link* link )
{ m_links.insert( link ); }
//! Remove link from set
void disconnect( Link* link )
{ m_links.erase( link ); }
//! Set of active links
LinkSet m_links;
//! Type of accepted messages
const TypeDef& m_msgType;
//! Slot method usind dynamic cast on message pointer
const Function m_dynamicCastFunction;
//! Slot method using static cast on message pointer
const Function m_staticCastFunction;
};
template <class TObj, class TMsg,
void (TObj::*TMethod)(typename TMsg::Ptr, Link*)>
class SlotT : public Slot
{
public:
//! SlotT constructor with templated type
SlotT( TObj* obj )
: Slot(TMsg::Type(),
std::bind( &SlotT<TObj,TMsg,TMethod>::dynamicCastFunction, obj,
std::placeholders::_1,
std::placeholders::_2 ),
std::bind( &SlotT<TObj,TMsg,TMethod>::staticCastFunction, obj,
std::placeholders::_1,
std::placeholders::_2 ) )
{
}
private:
//! dynamic cast function
static void dynamicCastFunction( TObj* obj,
typename Message::Ptr msg,
Link* link )
{
typename TMsg::Ptr m = std::dynamic_pointer_cast<TMsg>(msg);
if( m && obj )
(obj->*TMethod)(m, link);
}
//! static cast function
static void staticCastFunction( TObj* obj,
typename Message::Ptr msg,
Link* link )
{
typename TMsg::Ptr m = std::static_pointer_cast<TMsg>(msg);
if( m && obj )
(obj->*TMethod)(m, link);
}
};