問題を解決しました。これは非常に簡潔なコードです。シグナルは、発信する可能性のあるメッセージ タイプを単純に定義するテンプレート クラスでもあります。したがって、シグナルをスロットに接続する場合、Link コンストラクターは、シグナルによって発行されたメッセージ タイプとスロットによって受け入れられたメッセージ タイプのポリモーフィックな互換性をチェックできます。次に、動的キャストが必要かどうかに関係なく、適切な関数ポインターをコピーします。ここで示していないのは、Type クラスと、それを使用してメッセージ タイプの互換性をチェックする方法です。
その答えは、2 つのスロット関数とその関数ポインターを定義する方法でした。
クラスでスロットを定義する方法の例を次に示します。
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);
}
};