代码之家  ›  专栏  ›  技术社区  ›  Eugene

不包括升压信号呼叫

  •  1
  • Eugene  · 技术社区  · 15 年前

    有一个信号和几个带插槽的物体。我想在一个对象调用信号并阻塞自己的连接时实现该行为。我想一个小片段会更有用:

    
    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签名定义调用方法?
    1 回复  |  直到 15 年前
        1
  •  4
  •   Éric Malenfant    15 年前

    对于你的第一个问题:我不知道一个“标准的助推方式”来实现你想要的。你可以把你的问题发到 boost users mailing list .

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

    一些建议,没有特别的顺序:

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

    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_连接,并返回一个共享的M_-ptr-to-M_信号,该信号具有一个自定义的删除程序,可以解除M_连接的阻塞。

    遗憾的是,这并不能为调用者提供一个良好的语法。它看起来像:

    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"));