我想boost::signals2
用来处理我的 C++ 应用程序中的事件通知。我希望实现与浏览器 DOM 事件具有相似功能的东西,特别是能够停止事件传播的能力,以便当前接收器是最后一个知道信号的接收器,并且不会调用后续接收器。(请参阅http://www.w3.org/TR/DOM-Level-3-Events/#events-event-type-stopImmediatePropagation了解更多关于它是如何在浏览器中工作的)
我有一个App
带有信号的假设类,称为thingHappened
. 很可能只有一个App
实例,其他几个Widget
不同类型的类将connect
接收thingHappened
通知ThingEvent
。有时小部件想要消耗(停止) sThingEvent
以便不Widget
通知其他 s。
起初我想知道我是否可以通过 a 来实现这一点,shared_connection_block
但现在我明白这一次只会抑制一个连接。最初我将 a 传递shared_ptr<ThingEvent>
给我的信号,但是一旦调用了信号,就无法干预它的传播。如果我传递一个 shared_ptr,我可以让信号接收器检查事件的值并在它已设置时返回,但我不想将该细节推送给我的库的用户。
我找到的解决方案是ThingEvent
在堆栈上传递 a 以便为每个接收器复制它。如果我设置mStopPropagation
了事件,那么当它被销毁时,我可以抛出异常并且信号调用终止。这样做的缺点是我在调用信号的时候需要我自己的 try/catch,而且从风格上讲,这意味着我将 anexception
用于非特殊目的。有没有更好的办法?
这是我假设的App
课程,带有一个信号thingHappened
:
class App
{
public:
boost::signals2::signal<void (class ThingEvent)> thingHappened;
};
我的ThingEvent
类,有一些关于事件的数据(例如类型)和一个mStopPropagation
属性,如果在析构函数中设置它会导致抛出异常:
class ThingEvent
{
public:
ThingEvent(string type): mType(type), mStopPropagation(false) { }
~ThingEvent()
{
if (mStopPropagation) {
throw exception();
}
}
void stopPropagation() { mStopPropagation = true; }
string getType() { return mType; }
private:
string mType;
bool mStopPropagation;
};
这是一个示例信号使用者 a ,如果类型为Widget
,它将调用stopPropagation()
a :event
"goat"
class Widget
{
public:
Widget(string name): mName(name) {}
~Widget() {}
void thingHappened(ThingEvent thing)
{
cout << thing.getType() << " thingHappened in widget " << mName << endl;
if (thing.getType() == "goat") {
thing.stopPropagation();
}
}
string getName()
{
return mName;
}
private:
string mName;
};
最后,这是一个使用这些类的快速main()
函数:
int main()
{
App app;
Widget w1("1");
Widget w2("2");
Widget w3("3");
boost::signals2::connection c1 = app.thingHappened.connect(boost::bind(&Widget::thingHappened, &w1, _1));
boost::signals2::connection c2 = app.thingHappened.connect(boost::bind(&Widget::thingHappened, &w2, _1));
boost::signals2::connection c3 = app.thingHappened.connect(boost::bind(&Widget::thingHappened, &w3, _1));
// all three widgets will receive this
app.thingHappened(ThingEvent("otter"));
{
// suppress calls to c2
boost::signals2::shared_connection_block block(c2,true);
// only w1 and w3 will receive this
app.thingHappened(ThingEvent("badger"));
}
// Widgets call ThingEvent::stopPropagation() if the type is "goat"
try {
// only w1 will receive this
app.thingHappened(ThingEvent("goat"));
} catch (exception &e) {
// ThingEvent's destructor throws if mStopPropagation is true
std::cout << "exception thrown by thingHappened(goat)" << std::endl;
}
return 0;
}
如果你手头有提升(我使用的是 1.44)并且你想编译它,完整的代码和 Makefile 在https://gist.github.com/1445230