【问题标题】:Excluding boost signal calling不包括升压信号调用
【发布时间】:2009-10-09 05:58:40
【问题描述】:

有一个信号和几个带有槽的对象。我想实现当一个对象调用信号并阻止它自己的连接时的行为。我想一个小的 sn-p 会提供更多信息:

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 方法?

【问题讨论】:

  • 我不明白你想要达到什么目的。在您的示例中,连接归 SlotObject 所有,因此我在 Call() 中看到的 block() 的唯一用例是中断递归,即 slot() 调用 SlotObject::Call()。是这样吗?
  • 我正在尝试在多个对象之间同步添加项目操作。每个对象都可以添加项目,并且必须向所有其他对象发送通知。 IE。插槽不是 Call()。 Call() 需要向除所有者之外的所有对象发送通知。我知道它可以通过更简单的方式实现,只是想知道语法。

标签: c++ templates boost boost-signals


【解决方案1】:

对于您的第一个问题:我不知道实现您想要的“标准提升方式”。您可以将您的问题发布到boost users mailing list

第二个问题:没有可变模板和右值引用,转发总是很麻烦。

一些建议,排名不分先后:

1) 您可以查看 boost/signal.hpp 和 boost/signals/ 中的文件,以了解如何使用预处理器完成此类工作,但这里有一个部分实现来展示这个想法(警告:未经测试):

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 的用户放弃一点语法上的好处,那么其他的事情都是可能的。一种是使用 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"));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-29
    • 1970-01-01
    • 1970-01-01
    • 2012-06-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多