我想为向插槽发出信号的模块(线程)创建 boost::signals2 的包装类。即,一个模块应该通过从我的 Signal 类继承来获得典型的简单信号功能(例如公共 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)无法编译。它打破了 boosts slot_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。虽然有一个编译器警告“带有可能不安全的参数的函数调用 - 此调用依赖于调用者来检查传递的值是否正确。” 在 boost 的 singals2 auto_buffer.hpp 中。
那么这里的实际问题是什么以及如何解决呢?为什么这适用于 boost::ref 以及为什么没有它就无法编译?
我什至不确定整个设计理念是否有用。最初的想法是将整个信令/插槽的东西隐藏在一个超类中,并专注于签名(并包括生命周期管理)。
关于 boost 的信号 2 的另一个问题:singals2 connect() 方法引用了一个插槽。这在内部是如何处理的。它是使用连接插槽的引用还是复制插槽?这很重要,因为我的插槽处理动态分配的内存。