Skip to content

Instantly share code, notes, and snippets.

@RandomEtc
Created December 7, 2011 23:17
Show Gist options
  • Save RandomEtc/1445230 to your computer and use it in GitHub Desktop.
Save RandomEtc/1445230 to your computer and use it in GitHub Desktop.
Using Boost Signals2 to pass messages, return true to cancel propagation
// see http://stackoverflow.com/questions/8424388/any-way-to-cancel-signal-propagation-in-boost-signals2-without-exceptions for origins
#include <iostream>
#include <string>
#include <exception>
#include <boost/signals2.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
using namespace std;
typedef boost::shared_ptr<class ThingEvent> ThingEventRef;
class ThingEvent
{
public:
static ThingEventRef create(string type)
{
return ThingEventRef(new ThingEvent(type));
}
~ThingEvent()
{
// std::cout << "~ThingEvent(" << mType << ")" << std::endl;
}
string getType() { return mType; }
bool shouldStopPropagation() { return mStopPropagation; }
void stopPropagation() { mStopPropagation = true; }
private:
ThingEvent(string type): mType(type), mStopPropagation(false)
{
// std::cout << "ThingEvent(" << mType << ")" << std::endl;
}
ThingEvent(const ThingEvent &event): mType(event.mType), mStopPropagation(event.mStopPropagation)
{
// std::cout << "ThingEvent(" << mType << ")" << std::endl;
}
string mType;
bool mStopPropagation;
};
struct MyCombiner {
typedef void result_type;
MyCombiner(): mEvent(ThingEvent::create("")) {}
MyCombiner(ThingEventRef event): mEvent(event) {}
template <typename InputIterator> void operator()(InputIterator iter, InputIterator end) const {
for (; iter != end && !mEvent->shouldStopPropagation(); ++iter) {
*iter;
}
}
ThingEventRef mEvent;
};
typedef boost::signals2::signal<void (ThingEventRef), MyCombiner> ThingSignal;
class App
{
public:
ThingSignal thingHappened;
};
class Widget
{
public:
Widget(string name): mName(name) {}
~Widget() {}
void thingHappened(ThingEventRef thing)
{
cout << thing->getType() << " thingHappened in widget " << mName << endl;
}
string getName() { return mName; }
private:
string mName;
};
class GoatCancelingWidget
{
public:
GoatCancelingWidget(string name): mName(name) {}
~GoatCancelingWidget() {}
void thingHappened(ThingEventRef thing)
{
cout << thing->getType() << " thingHappened in GoatCancelingWidget " << mName << endl;
// stop propagation on "goat" events, otherwise carry on...
if (thing->getType() == "goat") {
thing->stopPropagation();
}
}
string getName() { return mName; }
private:
string mName;
};
class GoatExceptionWidget
{
public:
GoatExceptionWidget(string name): mName(name) {}
~GoatExceptionWidget() {}
void thingHappened(ThingEventRef thing)
{
cout << thing->getType() << " thingHappened in GoatExceptionWidget " << mName << endl;
// throw exception on goat events
if (thing->getType() == "goat") {
throw exception();
}
}
string getName() { return mName; }
private:
string mName;
};
int main()
{
App app;
Widget w1("1");
GoatCancelingWidget w2("2");
GoatExceptionWidget w3("3");
boost::signals2::connection c1 = app.thingHappened.connect(boost::bind(&Widget::thingHappened, &w1, _1));
boost::signals2::connection c2 = app.thingHappened.connect(boost::bind(&GoatCancelingWidget::thingHappened, &w2, _1));
boost::signals2::connection c3 = app.thingHappened.connect(boost::bind(&GoatExceptionWidget::thingHappened, &w3, _1));
// all three widgets will receive this
ThingEventRef event = ThingEvent::create("otter");
cout << "three widgets should hear about otter:" << endl;
app.thingHappened(event);
cout << endl;
{
// suppress calls to c2
boost::signals2::shared_connection_block block(c2,true);
// only w1 and w3 will receive this
event = ThingEvent::create("badger");
cout << "widgets 1 and 3 should hear about badger:" << endl;
app.thingHappened(event);
cout << endl;
}
// GoatCancelingWidget stops propagation if the type is "goat"
// so with the custom combiner that can inspect the event
// only w1 and w2 will receive this
event = ThingEvent::create("goat");
app.thingHappened.set_combiner(MyCombiner(event));
cout << "widgets 1 and 2 should hear about goat:" << endl;
app.thingHappened(event);
cout << endl;
return 0;
}
# don't hate me for this Makefile, at least I provided one
BOOST_PATH = /Users/tom/Documents/Code/Cinder/Cinder/boost
main: main.o
g++ -o main main.o
main.o: main.cpp
g++ -c -I$(BOOST_PATH) -o main.o main.cpp
clean:
rm -f main.o
rm -f main
% ./main
three widgets should hear about otter:
otter thingHappened in widget 1
otter thingHappened in GoatCancelingWidget 2
otter thingHappened in GoatExceptionWidget 3
widgets 1 and 3 should hear about badger:
badger thingHappened in widget 1
badger thingHappened in GoatExceptionWidget 3
widgets 1 and 2 should hear about goat:
goat thingHappened in widget 1
goat thingHappened in GoatCancelingWidget 2
%
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment