Created
December 7, 2011 23:17
-
-
Save RandomEtc/1445230 to your computer and use it in GitHub Desktop.
Using Boost Signals2 to pass messages, return true to cancel propagation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
% ./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