使用 Boost::Signals for C++ Eventing 的完整示例

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/768351/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:12:19  来源:igfitidea点击:

Complete example using Boost::Signals for C++ Eventing

c++boost-signals

提问by Chris Andrews

I'm aware of the tutorial at boost.org addressing this: Boost.org Signals Tutorial, but the examples are not complete and somewhat over simplified. The examples there don't show the include files and some sections of the code are a little vague.

我知道 boost.org 上的教程解决了这个问题: Boost.org Signals Tutorial,但这些示例并不完整,而且有些过于简化。那里的示例没有显示包含文件,并且代码的某些部分有点模糊。

Here is what I need:
ClassA raises multiple events/signals
ClassB subscribes to those events (Multiple classes may subscribe)

这是我需要的:
ClassA 引发多个事件/信号
ClassB 订阅这些事件(多个类可以订阅)

In my project I have a lower-level message handler class that raises events to a business class that does some processing of those messages and notifies the UI (wxFrames). I need to know how these all might get wired up (what order, who calls who, etc).

在我的项目中,我有一个较低级别的消息处理程序类,它将事件引发到一个业务类,该业务类对这些消息进行一些处理并通知 UI (wxFrames)。我需要知道这些都是如何连接起来的(什么顺序,谁打电话给谁,等等)。

回答by MattyT

The code below is a minimal working example of what you requested. ClassAemits two signals; SigAsends (and accepts) no parameters, SigBsends an int. ClassBhas two functions which will output to coutwhen each function is called. In the example there is one instance of ClassA(a) and two of ClassB(band b2). mainis used to connect and fire the signals. It's worth noting that ClassAand ClassBknow nothing of each other (ie they're not compile-time bound).

下面的代码是您请求的最小工作示例。 ClassA发出两个信号;SigA发送(并接受)无参数,SigB发送int. ClassB有两个函数,cout当每个函数被调用时将输出到。在该例子中存在的一个实例ClassAa)和两个ClassBbb2)。 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);
}

The output:

输出:

Foo
Bar: 4
Bar: 4

For brevity I've taken some shortcuts that you wouldn't normally use in production code (in particular access control is lax and you'd normally 'hide' your signal registration behind a function like in KeithB's example).

为简洁起见,我采用了一些您通常不会在生产代码中使用的快捷方式(特别是访问控制松懈,您通常会将您的信号注册“隐藏”在像 KeithB 示例中的函数后面)。

It seems that most of the difficulty in boost::signalis in getting used to using boost::bind. It isa bit mind-bending at first! For a trickier example you could also use bindto hook up ClassA::SigAwith ClassB::PrintInteven though SigAdoes notemit an int:

似乎大部分困难在于boost::signal习惯使用boost::bind. 这一个有点令人费解的第一!对于一个更为复杂的例子,你也可以使用bind挂钩ClassA::SigAClassB::PrintInt即使SigA没有没有发出int

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

Hope that helps!

希望有帮助!

回答by KeithB

Here is an example from our codebase. Its been simplified, so I don't guarentee that it will compile, but it should be close. Sublocation is your class A, and Slot1 is your class B. We have a number of slots like this, each one which subscribes to a different subset of signals. The advantages to using this scheme are that Sublocation doesn't know anything about any of the slots, and the slots don't need to be part of any inheritance hierarchy, and only need implement functionality for the slots that they care about. We use this to add custom functionality into our system with a very simple interface.

这是我们代码库中的一个示例。它被简化了,所以我不保证它会编译,但它应该是接近的。Sublocation 是您的 A 类,Slot1 是您的 B 类。我们有许多这样的槽,每个槽都订阅不同的信号子集。使用这种方案的优点是 Sublocation 不知道任何关于任何插槽的信息,并且插槽不需要成为任何继承层次结构的一部分,只需要为他们关心的插槽实现功能。我们使用它通过一个非常简单的界面将自定义功能添加到我们的系统中。

Sublocation.h

子位置.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

子位置.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

插槽1.h

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

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

Slot1.C

插槽1.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)
{
  // ...
}

回答by éric Malenfant

回答by Vihaan Verma

Boost like QT provides its own implementation of signals and slots. Following are some example of its implementation.

像 QT 一样的 Boost 提供了自己的信号和插槽实现。以下是其实现的一些示例。

Signal and Slot connection for namespace

命名空间的信号和槽连接

Consider a namespace called GStreamer

考虑一个名为 GStreamer 的命名空间

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

Here is how to create and trigger the signal

下面是如何创建和触发信号

 #include<boost/signal.hpp>

 ...

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

Signal and Slot connection for a Class

类的信号和插槽连接

Consider a Class called GSTAdaptor with function called func1 and func2 with following signature

考虑一个名为 GSTAdaptor 的类,其函数名为 func1 和 func2,其签名如下

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

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

Here is how to create and trigger the signal

下面是如何创建和触发信号

#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

回答by psalong

When compiling MattyT's example with newer boost (f.e. 1.61) then it gives a warning

当使用较新的 boost (fe 1.61) 编译 MattyT 的示例时,它会发出警告

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." 

So either you define BOOST_SIGNALS_NO_DEPRECATION_WARNING to suppress the warning or you could easily switch to boost.signal2 by changing the example accordingly:

因此,要么您定义 BOOST_SIGNALS_NO_DEPRECATION_WARNING 来抑制警告,要么您可以通过相应地更改示例轻松切换到 boost.signal2:

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

using namespace boost::signals2;
using namespace std;