web-dev-qa-db-fra.com

Exemple complet d'utilisation de Boost :: Signals for C++ Eventing

Je connais le tutoriel sur boost.org qui aborde ceci: Tutoriel sur les signaux Boost.org , mais les exemples ne sont pas complets et ont été quelque peu simplifiés. Les exemples ne montrent pas les fichiers d’inclusion et certaines sections du code sont un peu vagues.

Voici ce dont j'ai besoin:
ClassA génère plusieurs événements/signaux
ClassB est abonné à ces événements (plusieurs classes peuvent s'abonner) 

Dans mon projet, j'ai une classe de gestionnaire de messages de niveau inférieur qui génère des événements en une classe métier qui effectue un traitement de ces messages et notifie l'interface utilisateur (wxFrames). J'ai besoin de savoir comment tout cela pourrait être câblé (quel ordre, qui appelle qui, etc.).

55
Chris Andrews

Le code ci-dessous est un exemple de travail minimal de ce que vous avez demandé. ClassA émet deux signaux; SigA n'envoie (et n'accepte) aucun paramètre, SigB envoie un int. ClassB a deux fonctions qui vont sortir cout quand chaque fonction est appelée. Dans l'exemple, il existe une instance de ClassA (a) et deux de ClassB (b et b2). main est utilisé pour connecter et déclencher les signaux. Il est à noter que ClassA et ClassB ne savent rien l'un de l'autre (c'est-à-dire qu'ils ne sont pas liés à la compilation).

#include <boost/signal.hpp>
#include <boost/bind.hpp>
#include <iostream>

using namespace boost;
using namespace std;

struct ClassA
{
    signal<void ()>    SigA;
    signal<void (int)> SigB;
};

struct ClassB
{
    void PrintFoo()      { cout << "Foo" << endl; }
    void PrintInt(int i) { cout << "Bar: " << i << endl; }
};

int main()
{
    ClassA a;
    ClassB b, b2;

    a.SigA.connect(bind(&ClassB::PrintFoo, &b));
    a.SigB.connect(bind(&ClassB::PrintInt, &b,  _1));
    a.SigB.connect(bind(&ClassB::PrintInt, &b2, _1));

    a.SigA();
    a.SigB(4);
}

Le résultat:

 Foo 
 Barre: 4 
 Barre: 4 

Par souci de brièveté, j'ai pris des raccourcis que vous n'utiliseriez pas normalement dans le code de production (notamment, le contrôle d'accès est laxiste et vous devez normalement "masquer" l'enregistrement du signal derrière une fonction comme dans l'exemple de KeithB).

Il semble que le plus difficile dans boost::signal consiste à s'habituer à utiliser boost::bind. C'est est un peu hallucinant au début! Pour un exemple plus délicat, vous pouvez également utiliser bind pour connecter ClassA::SigA à ClassB::PrintInt même si SigA ne pas émet un int :

a.SigA.connect(bind(&ClassB::PrintInt, &b, 10));

J'espère que cela pourra aider!

86
MattyT

Voici un exemple de notre base de code. Son été simplifié, donc je ne garantis pas qu'il compilera, mais il devrait être proche. La sous-location correspond à votre classe A et Slot1 à votre classe B. Nous avons un certain nombre d'emplacements comme celui-ci, chacun d'eux s'abonnant à un sous-ensemble différent de signaux. L'utilisation de ce schéma présente les avantages suivants: la sous-location ne connaît rien des emplacements, et les emplacements n'ont pas besoin de faire partie d'une hiérarchie d'héritage et nécessitent uniquement une fonctionnalité d'implémentation pour les emplacements qui les intéressent. Nous l'utilisons pour ajouter des fonctionnalités personnalisées à notre système avec une interface très simple.

Sublocation.h

class Sublocation 
{
public:
  typedef boost::signal<void (Time, Time)> ContactSignal;
  typedef boost::signal<void ()> EndOfSimSignal;

  void endOfSim();
  void addPerson(Time t, Interactor::Ptr i);

  Connection addSignalContact(const ContactSignal::slot_type& slot) const;
  Connection addSignalEndOfSim(const EndOfSimSignal::slot_type& slot) const;    
private:
  mutable ContactSignal fSigContact;
  mutable EndOfSimSignal fSigEndOfSim;
};

Sublocation.C

void Sublocation::endOfSim()
{
  fSigEndOfSim();
}

Sublocation::Connection Sublocation::addSignalContact(const ContactSignal::slot_type& slot) const
{
  return fSigContact.connect(slot);
}

Sublocation::Connection Sublocation::addSignalEndOfSim(const EndOfSimSignal::slot_type& slot) const
{
  return fSigEndOfSim.connect(slot);
}

Sublocation::Sublocation()
{
  Slot1* slot1 = new Slot1(*this);
  Slot2* slot2 = new Slot2(*this);
}

void Sublocation::addPerson(Time t, Interactor::Ptr i)
{
  // compute t1
  fSigOnContact(t, t1);
  // ...
}

Slot1.h

class Slot1
{
public:
  Slot1(const Sublocation& subloc);

  void onContact(Time t1, Time t2);
  void onEndOfSim();
private:
  const Sublocation& fSubloc;
};

Slot1.C

Slot1::Slot1(const Sublocation& subloc)
 : fSubloc(subloc)
{
  subloc.addSignalContact(boost::bind(&Slot1::onContact, this, _1, _2));
  subloc.addSignalEndSim(boost::bind(&Slot1::onEndSim, this));
}


void Slot1::onEndOfSim()
{
  // ...
}

void Slot1::onContact(Time lastUpdate, Time t)
{
  // ...
}
11
KeithB

Avez-vous regardé boost/libs/signaux/example ?

6
Éric Malenfant

Boost comme QT fournit sa propre implémentation de signaux et de slots. Voici quelques exemples de sa mise en œuvre.

Connexion signal et slot pour un espace de noms

Considérons un espace de noms appelé GStreamer

 namespace GStremer
 {
  void init()
  {
  ....
  }
 }

Voici comment créer et déclencher le signal

 #include<boost/signal.hpp>

 ...

 boost::signal<void ()> sigInit;
 sigInit.connect(GStreamer::init);
 sigInit(); //trigger the signal

Connexion signal et slot pour une classe

Considérons une classe appelée GSTAdaptor avec une fonction appelée func1 et func2 avec la signature suivante

void GSTAdaptor::func1()
 {
 ...
 }

 void GSTAdaptor::func2(int x)
 {
 ...
 }

Voici comment créer et déclencher le signal

#include<boost/signal.hpp>
 #include<boost/bind.hpp>

 ...

 GSTAdaptor g;
 boost::signal<void ()> sigFunc1;
 boost::signal<void (int)> sigFunc2;

 sigFunc1.connect(boost::bind(&GSTAdaptor::func1, &g); 
 sigFunc2.connect(boost::bind(&GSTAdaptor::func2, &g, _1));

 sigFunc1();//trigger the signal
 sigFunc2(6);//trigger the signal
1
Vihaan Verma

Lors de la compilation de l’exemple de MattyT avec un boost plus récent (par exemple, 1.61), un avertissement s’affiche. 

error: #warning "Boost.Signals is no longer being maintained and is now deprecated. Please switch to Boost.Signals2. To disable this warning message, define BOOST_SIGNALS_NO_DEPRECATION_WARNING." 

Donc, soit vous définissez BOOST_SIGNALS_NO_DEPRECATION_WARNING pour supprimer l'avertissement, soit vous pouvez facilement passer à boost.signal2 en modifiant l'exemple en conséquence:

#include <boost/signals2.hpp>
#include <boost/bind.hpp>
#include <iostream>

using namespace boost::signals2;
using namespace std;
0
psalong