2009-04-20 3 views
54

私はboost.orgのチュートリアルである Boost.org Signals Tutorialを知っていますが、例は完全ではなく、幾分単純化されています。ここの例ではインクルードファイルが表示されず、コードのいくつかのセクションは少し曖昧です。ここで完全な例:Boost :: C++ Eventingのための信号

は、私は必要なものである:
にClassAは、複数のイベント/信号
ClassBのは、これらのイベントをサブスクライブ上げる(複数のクラスが加入することができる)

私のプロジェクトでは、私は低レベルのメッセージ・ハンドラ・クラスを持っていることこれらのメッセージの処理を行うビジネスクラスにイベントを提出し、UI(wxFrames)に通知します。私は、これらのすべてがどのように配線されているのかを知る必要があります(どのような順序、誰が誰を呼び出すかなど)。

答えて

82

以下のコードは、あなたが要求したものの最小の実例です。 ClassAは2つの信号を出力します。 SigAはパラメータを送信しません(受け入れます)。SigBintを送信します。 ClassBには、それぞれの関数が呼び出されるときにcoutに出力する2つの関数があります。この例では、ClassAa)のインスタンスと、ClassBbと)の2つのインスタンスがあります。 mainは信号の接続と起動に使用されます。 ClassAClassBはお互いに分かっていないことに注意する価値があります(つまり、はコンパイル時にはになりません)。

#include <boost/signal.hpp> 
#include <boost/bind.hpp> 
#include <iostream> 

using namespace boost; 
using namespace std; 

struct ClassA 
{ 
    signal<void()> SigA; 
    signal<void (int)> SigB; 
}; 

struct ClassB 
{ 
    void PrintFoo()  { cout << "Foo" << endl; } 
    void PrintInt(int i) { cout << "Bar: " << i << endl; } 
}; 

int main() 
{ 
    ClassA a; 
    ClassB b, b2; 

    a.SigA.connect(bind(&ClassB::PrintFoo, &b)); 
    a.SigB.connect(bind(&ClassB::PrintInt, &b, _1)); 
    a.SigB.connect(bind(&ClassB::PrintInt, &b2, _1)); 

    a.SigA(); 
    a.SigB(4); 
} 

出力:私はあなたが通常の生産コードで使用することはありませんいくつかのショートカットを撮影した簡潔にするために

 
Foo 
Bar: 4 
Bar: 4 

(特定のアクセス制御ではずさんであり、あなたと思います通常は「隠します」 KeithBの例のような機能の背後にあるシグナルの登録)。

boost::signalの難しさのほとんどは、boost::bindの使用に慣れているようです。それは最初はちょっと心配!トリッキーたとえば、あなたはまた、SigAないをしていてもClassB::PrintIntClassA::SigAをフックするbindを使用することができintを発する:

a.SigA.connect(bind(&ClassB::PrintInt, &b, 10)); 

助けホープ!

+0

関数をオーバーロードすることは可能ですか?もしそうなら、それを追加してもかまいません。 s.t. PrintNum(int)のようなものがあります。およびPrintNum(float)。 – pyInTheSky

+0

@pyInTheSky関数型(厳密な用語は不明): '(void(*)(int))&PrintNum' – Qix

6

boost/libs/signals/exampleを見ましたか?

+0

をありがとう!これらの例はやや良いですが、より大きく、より現実的な例があるのは良いことです。 –

11

ここでは、コードベースの例を示します。それは単純化されているので、私はそれがコンパイルされることを保証しませんが、それは近いはずです。 SublocationはあなたのクラスAであり、Slot1はあなたのクラスBです。私たちはこのようないくつかのスロットを持っています。それぞれが異なるシグナルのサブセットに加入しています。このスキームを使用する利点は、Sublocationがいずれのスロットについても何も知らず、スロットが継承階層の一部である必要がなく、気になるスロットの機能を実装するだけで済むという点です。これを使用して、非常にシンプルなインターフェイスでカスタム機能をシステムに追加します。

Sublocation.h

class Sublocation 
{ 
public: 
    typedef boost::signal<void (Time, Time)> ContactSignal; 
    typedef boost::signal<void()> EndOfSimSignal; 

    void endOfSim(); 
    void addPerson(Time t, Interactor::Ptr i); 

    Connection addSignalContact(const ContactSignal::slot_type& slot) const; 
    Connection addSignalEndOfSim(const EndOfSimSignal::slot_type& slot) const;  
private: 
    mutable ContactSignal fSigContact; 
    mutable EndOfSimSignal fSigEndOfSim; 
}; 

Sublocation.C

void Sublocation::endOfSim() 
{ 
    fSigEndOfSim(); 
} 

Sublocation::Connection Sublocation::addSignalContact(const ContactSignal::slot_type& slot) const 
{ 
    return fSigContact.connect(slot); 
} 

Sublocation::Connection Sublocation::addSignalEndOfSim(const EndOfSimSignal::slot_type& slot) const 
{ 
    return fSigEndOfSim.connect(slot); 
} 

Sublocation::Sublocation() 
{ 
    Slot1* slot1 = new Slot1(*this); 
    Slot2* slot2 = new Slot2(*this); 
} 

void Sublocation::addPerson(Time t, Interactor::Ptr i) 
{ 
    // compute t1 
    fSigOnContact(t, t1); 
    // ... 
} 

Slot1.h

class Slot1 
{ 
public: 
    Slot1(const Sublocation& subloc); 

    void onContact(Time t1, Time t2); 
    void onEndOfSim(); 
private: 
    const Sublocation& fSubloc; 
}; 

Slot1.C

Slot1::Slot1(const Sublocation& subloc) 
: fSubloc(subloc) 
{ 
    subloc.addSignalContact(boost::bind(&Slot1::onContact, this, _1, _2)); 
    subloc.addSignalEndSim(boost::bind(&Slot1::onEndSim, this)); 
} 


void Slot1::onEndOfSim() 
{ 
    // ... 
} 

void Slot1::onContact(Time lastUpdate, Time t) 
{ 
    // ... 
} 
+0

良い例。信号は可変ではなく、addSignalXXXはconstではないはずです - と強く主張していますが、それらはパブリックインターフェイスの一部であり、SubLocationの動作を確実に変更します。 – MattyT

+0

この点は議論の余地があると思います。あなたがどこから来ているのか分かります。一方、スロットを追加しても、サブロケーションの状態は直接変更されません。また、スロットが呼び出されたときに状態を変更したい場合は、サブロケーションの非コンストメンバ関数を呼び出す必要があります。これがコードレビューで提起された場合、私は自分のケースを述べたいが、それがコンセンサスだったなら、あなたが示唆した変更を行うことは気にしない。 – KeithB

+1

私もあなたの議論を見ることができます...おそらく興味深いコードレビューの議論だろう。 :) – MattyT

1

QTのようなブーストは、シグナルとスロットの独自の実装を提供します。以下にその実装例を示します。

信号と名前空間

用スロット接続のGStreamerと呼ばれる名前空間を考えてみましょう

namespace GStremer 
{ 
    void init() 
    { 
    .... 
    } 
} 
ここ

信号を生成し、トリガする方法です

#include<boost/signal.hpp> 

... 

boost::signal<void()> sigInit; 
sigInit.connect(GStreamer::init); 
sigInit(); //trigger the signal 

信号とクラス

用スロット接続

GSTAdaptorというクラスを楽しく使ってみましょうここでは、署名

void GSTAdaptor::func1() 
{ 
... 
} 

void GSTAdaptor::func2(int x) 
{ 
... 
} 

と次のように関数func1とfunc2のと呼ばれるctionは、新しいブーストでMattyTの例をコンパイルすると、信号

#include<boost/signal.hpp> 
#include<boost/bind.hpp> 

... 

GSTAdaptor g; 
boost::signal<void()> sigFunc1; 
boost::signal<void (int)> sigFunc2; 

sigFunc1.connect(boost::bind(&GSTAdaptor::func1, &g); 
sigFunc2.connect(boost::bind(&GSTAdaptor::func2, &g, _1)); 

sigFunc1();//trigger the signal 
sigFunc2(6);//trigger the signal 
0

を作成してトリガする方法です(f.e. 1.61)、それは警告

error: #warning "Boost.Signals is no longer being maintained and is now deprecated. Please switch to Boost.Signals2. To disable this warning message, define BOOST_SIGNALS_NO_DEPRECATION_WARNING." 

を与えるので、あなたは警告を抑制するためにBOOST_SIGNALS_NO_DEPRECATION_WARNINGを定義するか、あなたは簡単に応じて例を変更することにより、boost.signal2に切り替えることができ、次のいずれか

#include <boost/signals2.hpp> 
#include <boost/bind.hpp> 
#include <iostream> 

using namespace boost::signals2; 
using namespace std; 
関連する問題