c++ boost-signals

Ejemplo completo usando Boost:: Signals para C++ Eventing



boost-signals (5)

Soy consciente de que el tutorial en boost.org trata este tema: Tutorial de señales de Boost.org , pero los ejemplos no están completos y, en cierto modo, están demasiado simplificados. Los ejemplos no muestran los archivos de inclusión y algunas secciones del código son un poco vagas.

Esto es lo que necesito:
ClassA genera múltiples eventos / señales
ClassB se suscribe a esos eventos (varias clases pueden suscribirse)

En mi proyecto tengo una clase de manejador de mensajes de nivel inferior que genera eventos en una clase de negocios que procesa esos mensajes y notifica a la IU (wxFrames). Necesito saber cómo se pueden cablear todos estos (qué orden, quién llama a quién, etc.).



Al compilar el ejemplo de MattyT con un nuevo impulso (fe 1.61), se muestra una advertencia.

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."

Entonces, o bien define BOOST_SIGNALS_NO_DEPRECATION_WARNING para suprimir la advertencia o puede cambiar fácilmente a boost.signal2 cambiando el ejemplo en consecuencia:

#include <boost/signals2.hpp> #include <boost/bind.hpp> #include <iostream> using namespace boost::signals2; using namespace std;


Aquí hay un ejemplo de nuestro código base. Se ha simplificado, por lo que no garantizo que se compile, pero debería estar cerca. Sublocación es su clase A, y Slot1 es su clase B. Tenemos una serie de ranuras como esta, cada una de las cuales se suscribe a un subconjunto diferente de señales. Las ventajas de usar este esquema son que Sublocation no sabe nada de ninguna de las ranuras, y las ranuras no necesitan ser parte de ninguna jerarquía de herencia, y solo necesitan implementar la funcionalidad para las ranuras que les interesan. Usamos esto para agregar funcionalidad personalizada a nuestro sistema con una interfaz muy simple.

Sublocación.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; };

Sublocación.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) { // ... }


Boost como QT proporciona su propia implementación de señales y slots. Los siguientes son algunos ejemplos de su implementación.

Conexión de señal y ranura para espacio de nombres

Considere un espacio de nombres llamado GStreamer

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

Aquí es cómo crear y activar la señal.

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

Conexión de señal y ranura para una clase

Considere una clase llamada GSTAdaptor con una función llamada func1 y func2 con la siguiente firma

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

Aquí es cómo crear y activar la señal.

#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


El siguiente código es un ejemplo de trabajo mínimo de lo que solicitó. ClassA emite dos señales; SigA envía (y acepta) ningún parámetro, SigB envía un int . ClassB tiene dos funciones que se enviarán a cout cuando se llame a cada función. En el ejemplo hay una instancia de ClassA ( a ) y dos de ClassB ( b y b2 ). main se utiliza para conectar y disparar las señales. Vale la pena señalar que ClassA y ClassB no se conocen entre sí (es decir, no están vinculados al tiempo de compilación ).

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

La salida:

Foo Bar: 4 Bar: 4

Para mayor brevedad, tomé algunos atajos que normalmente no usaría en el código de producción (en particular, el control de acceso es laxo y normalmente ocultaría su registro de señal detrás de una función como en el ejemplo de KeithB).

Parece que la mayor parte de la dificultad en boost::signal está en acostumbrarse a usar boost::bind . Es un poco alucinante al principio! Para un ejemplo más complicado, también puede usar bind para conectar ClassA::SigA con ClassB::PrintInt aunque SigA no emita un int :

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

¡Espero que ayude!