public
Last active

Using Boost Signals2 to pass messages, return true to cancel propagation

  • Download Gist
Makefile
Makefile
1 2 3 4 5 6 7 8 9 10 11 12 13
# 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.cpp
C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
// 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;
}
output
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
% ./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
 
%

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.