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.).
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!
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)
{
// ...
}
Avez-vous regardé boost/libs/signaux/example ?
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
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;