boost::signals2
C++ アプリでイベント通知を処理するために使用したいと思います。ブラウザー DOM イベントと同様の機能を実装したいと考えています。具体的には、イベントの伝播を停止して、現在のレシーバーがシグナルについて知る最後のレシーバーになり、後続のレシーバーが呼び出されないようにする機能です。(これがブラウザーでどのように機能するかについて詳しくは、 http://www.w3.org/TR/DOM-Level-3-Events/#events-event-type-stopImmediatePropagationを参照してください)
と呼ばれる信号を持つ仮想App
クラスがありthingHappened
ます。通知を受信するさまざまなタイプの他のクラスがApp
いくつかあるため、インスタンスは1 つしかない可能性があります。他の に通知されないように、ウィジェットが を消費 (停止) したい場合があります。Widget
connect
thingHappened
ThingEvent
ThingEvent
Widget
最初は a でこれを達成できるかどうか疑問に思っていましたshared_connection_block
が、これは一度に 1 つの接続しか抑制しないことがわかりました。最初にシグナルに a を渡しましたshared_ptr<ThingEvent>
が、シグナルが呼び出されると、その伝播に介入する方法がありませんでした。shared_ptr を渡すと、シグナル レシーバーがイベントの値をチェックし、設定されている場合は返すことができますが、その詳細をライブラリのユーザーにプッシュしたくありません。
私が見つけた解決策はThingEvent
、スタックに a を渡して、各レシーバーにコピーされるようにすることです。イベントを設定mStopPropagation
すると、イベントが破棄されたときに例外がスローされ、シグナル呼び出しが終了します。これの欠点は、シグナルが呼び出された時点で独自の try/catch が必要なことです。スタイル的にはexception
、例外的な目的で を使用していることを意味します。より良い方法はありますか?
これが私の架空の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;
};
タイプがの場合Widget
に を呼び出すサンプル シグナル コンシューマ a を次に示します。stopPropagation()
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にあります。