スロットにシグナルを送信するモジュール (スレッド) 用の 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() メソッドはスロットへの参照を取ります。これは内部でどのように処理されますか。接続されたスロットの参照を使用しますか、それともスロットのコピーを作成しますか? 私のスロットは動的に割り当てられたメモリを処理するため、これは重要です。