0

スロットにシグナルを送信するモジュール (スレッド) 用の boost::signals2 のラッパー クラスを作成したいと考えています。つまり、モジュールは Signal クラスから継承することによって、典型的な単純なシグナル機能 (例えば public connect(...) メソッド) を取得する必要があります。また、使用されている実際のシグナルスロットの実装も隠したいと思います。

具体的なスロットは、その署名を定義するテンプレート パラメーターを持つ汎用スロット基本クラスから継承します。スロットは、適切なシグネチャを持つ単なるファンクタです。

この質問は、この質問に多少関連しています。スロットは shared_ptr として保存され、ライフタイム管理が必要です。つまり、Signal クラスは、シグナル自体が存在する限りスロットを存続させるために、スロットへの参照を保持する必要があります。したがって、std::functions などに接続できません。スロット基本クラスの shared_ptrs を接続する必要があります。

これまでのところスレッドセーフなしの私の現在のアプローチ(MSVC 2010):

template<class FunSig>
class Slot;

template<class R>
class Slot<R()>
{
public:
    typedef R Ret_type;

public:
    virtual ~Slot() {}
    virtual Ret_type operator()() = 0;
};

template<class R, class A1>
class Slot<R(A1)>
{
public:
    typedef R Ret_type;
    typedef A1 Arg1_type;

public:
    virtual ~Slot() {}
    virtual Ret_type operator()(Arg1_type) = 0;
};

// and so forth for more arguments


/*
Signalling class.
This class is basically a wrapper for the boost::signals2 class with 
lifetime management for slots.
Slots are connected by a shared_ptr which gets stored
in a std::vector to ensure that a slot exists at least as long as the signal.
*/
template<class FunSig>
class Signal
{
public:
    typedef Slot<FunSig> Slot_type;
    typedef boost::signals2::signal<FunSig> BoostSignal;
    typedef typename BoostSignal::slot_type BoostSlot;

public:
    virtual ~Signal() {}

    void connectSlot(std::shared_ptr<Slot_type> slot_ptr);

protected:
    //void emitSignal( ... );
    //void disconnectAllSlots();

private:
    BoostSignal sig_;

    /// vector of shared_ptr to slots for lifetime management
    std::vector<std::shared_ptr<Slot_type> > slotsVec_;
};


template<class FunSig>
void Signal<FunSig>::connectSlot(std::shared_ptr<Slot_type> slot_ptr)
{
    sig_.connect(*slot_ptr); // version A: compiler error

    // OR

    sig_.connect(boost::ref(*slot_ptr)); // version B: warning, but compiles and runs


    // add slot pointer to vector of slots
    slotsVec_.push_back(slot_ptr);
}

このコード (バージョン A) はコンパイルされません。これは、boostslot_template.hpp 内と、connectSlot メソッドでマークされた行で中断されます。

error C2679: binary '=' : no operator found which takes a right-hand operand of type 'const Slot<FunSig>' (or there is no acceptable conversion)
1>          with
1>          [
1>              FunSig=void (const float &)

興味深いことに、代わりにバージョン B を使用すると、このコードはコンパイルおよび実行されます。つまり、boost::ref がスロットに渡されます。コンパイラの警告がありますが、「安全でない可能性のあるパラメーターを使用した関数呼び出し - この呼び出しは、渡された値が正しいことを確認するために呼び出し元に依存しています。」ブーストのsingals2 auto_buffer.hppで。

では、ここでの実際の問題とその解決方法は何ですか? なぜこれは boost::ref で動作し、それなしではコンパイルできないのはなぜですか?

デザインのアイデア全体が役に立つかどうかさえ確信が持てません。当初のアイデアは、スーパークラスにシグナリング/スロット全体を隠し、署名に焦点を当てる (そしてライフタイム管理を含める) ことでした。

ブーストの signal2 に関する追加の質問: singals2 connect() メソッドはスロットへの参照を取ります。これは内部でどのように処理されますか。接続されたスロットの参照を使用しますか、それともスロットのコピーを作成しますか? 私のスロットは動的に割り当てられたメモリを処理するため、これは重要です。

4

2 に答える 2

1

警告 C4996 を意味していると思います。これは、Microsoft の C++ 標準ライブラリ実装の機能であり、安全でない可能性のある引数を使用して標準アルゴリズムがコンパイルされると警告が表示されます。たとえば、このスニペットでは、十分なサイズのsourceandに対して呼び出し元が責任を負いtargetます。

int source[3] = { 1, 2, 3 };
int target[3];
std::copy(source, source + 3, target);

Boost.Signals2 によってすでに提供されている機能を複製しないでください。ライブラリは、シグナルに接続された「スロット」の洗練されたライフタイム管理を提供します。docs を読むと、彼らはこの側面の非常に細かい制御を予見しています。また、Boost.Signals2 のスレッド セーフという非常に興味深い機能が失われます。自分自身に対するスレッド セーフな挿入と削除を管理する必要がありslotVec_ますが、これは重要な作業です...

私は自分でvexabstract_multicast_delegateと呼ばれる同様の抽象化ライブラリに取り組んでabstract_signalvex/functional/contractsます。に基づく実装signals2::signalは、 にありvex/functional/implementation/bs2_signal.hます。ただし、これはまだ遊び場です。別の実装も試しています...

編集: 申し訳ありませんが、codeplex の hg リポジトリの先端を指す方法がわかりません。昨日から多くの変更があったため、リンクを削除する必要がありました...

于 2013-04-27T10:59:43.837 に答える
0

この質問は、ここで別のコンテキストで回答されています。

実際には std::ref または boost::ref を使用する必要があります。これは、boost::signals2 connect メソッドがその引数をコピーするためです。ただし、クラス Slot は抽象クラスであるため、コピーできません。したがって、スロットをコピー可能にするため、boost::ref を使用することをお勧めします。

于 2013-05-02T08:28:29.967 に答える