2009-10-09 8 views
1

Il y a un signal et plusieurs objets avec des emplacements. Je veux implémenter le comportement quand un objet appelle le signal et bloque sa propre connexion. Je suppose qu'un petit extrait sera plus informatif:À l'exclusion de l'appel du signal d'amplification

 

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; 
}; 
 

Les questions:

  1. Y at-il une approche standard avec des trucs coup de pouce? Est-ce que je réinvente la roue?
  2. Comment définir la méthode d'appel avec la signature TSignal?
+0

Je ne comprends pas ce que vous essayez d'atteindre. Dans votre exemple, la connexion appartient à SlotObject, donc le seul cas d'utilisation que je vois pour block() dans Call() serait d'annuler la récursivité, c'est-à-dire que slot() appelle SlotObject :: Call(). Est-ce le cas? –

+0

J'essaie de synchroniser l'ajout d'éléments entre plusieurs objets. Chaque objet peut ajouter des éléments et envoyer des notifications à tous les autres. C'est à dire. le slot n'est pas Call(). Call() est nécessaire pour envoyer des notifications à tous les objets sauf le propriétaire. Je sais qu'il peut être mis en œuvre par des moyens plus simples, juste s'interroger sur la syntaxe. – Eugene

Répondre

4

Pour votre première question: Je ne suis pas au courant d'un «moyen standard boost» pour réaliser ce que vous voulez. Vous pouvez poster votre question au boost users mailing list.

Pour votre deuxième question: Sans modèles varidiques et références rvalue, le transfert est toujours fastidieux.

Quelques suggestions, sans ordre particulier:

1) Vous pouvez regarder le coup de pouce/signal.hpp et les fichiers Boost/signaux/pour avoir une idée de la façon dont ce genre de choses peut être fait avec le préprocesseur, mais voici une mise en œuvre partielle pour montrer l'idée (avertissement: non testé):

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) Si vous êtes prêt à abandonner un peu de syntaxe nicety pour les utilisateurs de SlotObject, d'autres choses sont possibles. L'une consiste à enrouler l'appel sur le signal en utilisant la technique indiquée dans la documentation boost :: shared_ptr (http://www.boost.org/doc/libs/1_40_0/libs/smart_ptr/sp_techniques.html#wrapper), c.-à-d. Que votre méthode Call() bloque la connexion m_signal, et renvoie un shared_ptr à m_signal ayant un suppresseur personnalisé qui débloque m_connection. Malheureusement, cela ne donne pas une bonne syntaxe à l'appelant. Il ressemblerait à ceci:

SlotObject<signal<void(int, float)> > s = ...; 
s.Call()->operator()(1, 1.234); 

3) Une autre alternative est de demander à l'utilisateur de regrouper les arguments dans un tuple (j'utilise un boost::fusion::vector ci-dessous) sur le site d'appel, et utilisez boost::fusion:::fused pour les déballer et appelez le signal.

#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(); 
    } 

    //... 
}; 

Ce serait utilisé comme:

typedef SlotObject<boost::signal<void(int, float)> > SlotType; 
SlotType s = ...; 
s.Call(SlotType::ArgsType(1, "foo")); 
+0

Éric, merci beaucoup pour cette excellente réponse! – Eugene

Questions connexes