1

シグナルと、スロットのあるいくつかのオブジェクトがあります。1 つのオブジェクトがシグナルを呼び出し、それ自体の接続をブロックするときの動作を実装したいと考えています。小さなスニペットがより有益になると思います:


typedef boost::signal<void()> TSignal;

template<class TSignal>
class SlotObject
{
public:

    void Connect(boost::shared_ptr<TSignal> pSignal, boost::function slot)
    {
        m_connection = pSignal->connect(slot);
        m_pSignal = pSignal;
    }

    // How to define TSignal signature here?
    VOID Call()
    {
        m_connection.block();
        (*m_pSignal)();
        m_connection.unblock();
    }

    boost::shared_ptr<TSignal> m_pSignal;
    boost::signals::connection m_connection;
};

質問:

  1. いくつかのブーストのものを使用した標準的なアプローチはありますか? 車輪の再発明ですか?
  2. TSignal署名でCallメソッドを定義するには?
4

1 に答える 1

4

あなたの最初の質問について:私はあなたが望むものを達成するための「標準的なブースト方法」を知りません。ブーストユーザーのメーリングリストに質問を投稿できます。

2番目の質問:可変個引数テンプレートと右辺値参照がないと、転送は常に面倒です。

いくつかの提案、順不同:

1) boost/signal.hppとboost/signal /内のファイルを見て、この種のことをプリプロセッサでどのように実行できるかを理解することができますが、ここにそのアイデアを示すための部分的な実装があります(警告:未テスト)::

template<size_t Arity, class SignalT>
struct SlotBase;

template<class SignalT>
struct SlotBase<0, SignalT>
{
    typedef SignalT::slot_function_type SlotType;

    SlotBase(boost::shared_ptr<SignalT> S, SlotType F)
        : m_Signal(S), m_Connection(S->connect(F))){};

    void operator()()const
    {
        m_Connection.block();
        m_Signal();
        m_Connection.unblock()
    };

private:
    boost::shared_ptr<SignalT> > m_Signal;
    boost::signals::connection m_Connection;
};

template<class SignalT>
struct SlotBase<1, SignalT>
{
    // as above, except for operator()
    // ...

    void operator()(typename SignalT::arg1_type arg1)
    {
        m_Connection.block();
        m_Signal(arg1);
        m_Connection.unblock();
    };
};

template<class SignalT>
struct SlotBase<2, SignalT>
{
    // as above, except for operator()
    // ...

    void operator()(typename SignalT::arg1_type arg1, typename SignalT::arg2_type arg2)
    {
        m_Connection.block();
        m_Signal(arg1, arg2);
        m_Connection.unblock()
    };
};

// repeat for other arities
// ...

template<class SignalT>
class SlotObject : public SlotBase<SignalT::arity, SignalT>
{
    typedef SlotBase<SignalT::arity, SignalT> BaseType;

public:
    Slot(boost::shared_ptr<SignalT>S, 
         typename SignalT::slot_function_type F
    ) : BaseType(S, F)
    {}
};

2) SlotObjectのユーザーのために少し構文をあきらめても構わないと思っているなら、他のことが可能です。1つは、boost :: shared_ptrドキュメント( http://www.boost.org/doc/libs/1_40_0/libs/smart_ptr/sp_techniques.html#wrapper)に示されている手法を使用して、シグナルへの呼び出しをラップすることです。 Call()メソッドはm_connectionをブロックし、shared_ptrをm_signalに返し、m_connectionのブロックを解除するカスタム削除機能を備えています。

残念ながら、これは呼び出し元に適切な構文を提供しません。次のようになります。

SlotObject<signal<void(int, float)> > s = ...;
s.Call()->operator()(1, 1.234);

3)別の方法は、呼び出しサイトで引数をタプルにパッケージ化するようにユーザーに依頼し(以下では、 boost ::fusion :: vectorを使用しています)、 boost ::fusion:::fusedを使用してそれらを解凍します。信号を呼び出します。

#include <boost/function_types/parameter_types.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/mpl.hpp>
#include <boost/fusion/include/fused.hpp>
#include <boost/signal.hpp>
#include <boost/shared_ptr.hpp>

// Metafunction to extract the Signature template parameter
// from a boost::signal instantiation
// For example, SignatureOf<signal<void(int, float)>::type 
// is "void(int, float)"
template<class SignalT>
struct SignatureOf;

template<
    typename Signature, typename Combiner, typename Group,
    typename GroupCompare, typename SlotFunction
>
struct SignatureOf<
    boost::signal<Signature, Combiner, Group, GroupCompare, SlotFunction>
>
{
    typedef Signature type;
};

// The SlotObject    
template<class SignalT>
class SlotObject
{
public:
    typedef typename SignatureOf<SignalT>::type SignatureType;

    // Defines the "packed" parameters type corresponding
    // to the slot's signature
    // For example, for a SignalT of boost::signal<void(int, float)>
    // ArgsType is "boost::fusion::vector<int, float>"
    typedef typename boost::fusion::result_of::as_vector<
        typename boost::function_types::parameter_types<SignatureType>::type
    >::type ArgsType;

    void Call(ArgsType P)
    {
        m_Connection.block();
        boost::fusion::fused<SignalT&> f(*m_Signal);
        f(P);
        m_Connection.unblock();
    }

    //...
};

これは次のように使用されます。

typedef SlotObject<boost::signal<void(int, float)> > SlotType;
SlotType s = ...;
s.Call(SlotType::ArgsType(1, "foo"));
于 2009-10-15T14:05:08.883 に答える