0

次の問題で体系的な動的キャストを回避する方法を探しています。

アクションオブジェクトとメッセージオブジェクトがあります。アクションオブジェクトには、メッセージを発行するメソッドと、メッセージを受け入れる他のメソッドがあります。もちろん、派生したActionクラスとMessagesクラスがあります。オブジェクトとそのメソッドは、相互接続されたオブジェクトのネットワークを定義する構成ファイルに基づく文字列IDによって、実行時に動的に接続されます。

これは、引数の数とタイプに強い制約があるシグナルスロットシステムに相当します。すべての信号はクラスMessageから派生したメッセージを送信し、すべてのスロットはクラスMessageから派生したメッセージを受け入れます。

接続はNxNです。したがって、信号はマルチキャストであり、スロットは複数のソースからの信号を受け入れることができます。

現在の実装では、信号とスロット間の接続をインスタンス化するLinkクラスを使用します。シグナルとスロットはファンクターメンバー変数です。各Actionオブジェクトには2つのマップがあります。1つは文字列名から信号へ、もう1つは文字列名からスロットへ。インスタンスへのアクション名のグローバルマップもあります。ターゲットアクション(スロット)のリンクを追跡する利点は、インスタンスが破棄されたときにすべてのリンクを適切に切断することです。

最初のパスでは、構成ファイルで定義されたすべてのアクションインスタンスがインスタンス化されます。2番目のパスでは、信号をスロットに接続するリンクがインスタンス化されます。

問題は、リンクがインスタンス化されたときにのみメッセージタイプの一致チェックが実行され、必要な場合にのみ動的キャストが実行されるように、これをどのように実装するかです。

たとえば、メッセージベースクラスMとMのサブクラスM1およびM1のサブクラスM2がある場合、signal(M2)からslot(M1)またはslot(M)へのリンクは動的キャストを実行せず、リンクsignal(M1)またはsignal(M)からslot(M2)へは、動的キャストを実行します。スロットメソッドが呼び出されるのは、動的キャストが成功した場合のみです(nullptrは返されません)。

呼び出しごとに動的キャストが実行される実装は簡単です。可能であれば、これを回避するための解決策を探しています。

私の現在の理解では、動的バインディングのためにboost::signalsを使用することはできません。

4

1 に答える 1

0

問題を解決しました。これは非常に簡潔なコードです。シグナルは、発信する可能性のあるメッセージ タイプを単純に定義するテンプレート クラスでもあります。したがって、シグナルをスロットに接続する場合、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);
    }    
};
于 2012-06-20T10:27:28.623 に答える