包装的boost :: signals2与终身管理的通用插槽 [英] wrapper for boost::signals2 with lifetime management for generic slots

查看:419
本文介绍了包装的boost :: signals2与终身管理的通用插槽的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想为发射信号到插槽的模块(线程)创建一个包装类boost :: signals2。也就是说模块应该通过继承我的Signal类来获得典型的简单信令能力(例如公共连接(...)方法)。我还想隐藏所使用的实际信号时隙实现。

I would like to create a wrapper class for boost::signals2 for modules (threads) that emits signals to slots. I.e. a module should gain typical simple signalling capabilities (e.g. a public connect(...) method) by inheriting from my Signal class. I would also like to hide the actual signal-slot implementation that is used.

一个具体的插槽继承自一个通用的Slot基类,它具有定义其签名的模板参数。

A concrete slot inherits from a generic Slot base class which has a template parameter defining its signature. A slot is just a functor with the suitable signature.

这个问题在某种程度上与这个问题。槽被存储为shared_ptr并且需要生命周期管理。也就是说Signal类应该保持对槽的引用以保持其活动,只要信号本身退出。因此我不能连接std ::函数或类似。

This question is somewhat related to this question. Slots are stored as shared_ptr and lifetime management is required. I.e. the Signal class should hold a reference to the slot to keep it alive as long as the signal itself exits. Hence I cannot connect std::functions or similar. I have to connect shared_ptrs of the slot base class.

我目前的方法,没有线程安全性(MSVC 2010):

My current approach, without thread safety so far (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版)它打破了内部提升槽slot_template.hpp和在connectSlot方法中标记的行:

This code (version A) does not compile. It breaks inside boosts slot_template.hpp and at the line marked in the connectSlot method:

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。

Interestingly this code compiles and runs if version B is used instead - i.e. a boost::ref is passed of the slot. Though there is a compiler warning "Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct." in boost's singals2 auto_buffer.hpp.

那么这里的实际问题是什么,如何解决呢?为什么这与boost :: ref工作,为什么它不编译没有它?

So what is the actual problem here and how to solve it? Why does this work with boost::ref and why does it not compile without it?

我甚至不确定整个设计的想法是有用的。最初的想法是将整个信令/槽的东西隐藏在超类中,并专注于签名(并包括生命周期管理)。

I am even unsure it the whole design idea is useful. The original idea was to hide the whole signalling/slot stuff in a superclass and focus on the signature (and include lifetime management).

关于boost信号的另一个问题2: singals2 connect()方法引用一个槽。这是如何处理内部。它使用连接插槽的引用还是制作插槽的副本?这是很重要的,因为我的插槽处理动态分配的内存。

An additional question regarding boost's signals2: the singals2 connect() method takes a reference to a slot. How is this handled internally. Does it use a reference of the connected slot or does it make a copy of the slot? This is important as my slots handle dynamically allocated memory.

推荐答案

此问题已在不同的上下文中回答在这里

This question has been answered in a different context here.

实际上,必须使用std :: ref或boost :: ref,因为boost :: signals2 connect方法会复制其参数。但类Slot是不可复制的,因为它是一个抽象类。因此,使用boost :: ref是推荐的解决方案,因为它使插槽可复制。

Actually std::ref or boost::ref have to be used because boost::signals2 connect method copies its arguments. But the class Slot is not copyable as it is an abstract class. Hence using boost::ref is the recommended solution because it makes the slot copyable.

这篇关于包装的boost :: signals2与终身管理的通用插槽的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆