如何使用boost :: signals2存储和转发插槽?

Aus*_*ler 5 c++ boost-signals2

我有一个问题,我必须比我想要更早地实例化对象的实例,因为我需要通过一些深层所有权连接信号槽,我想提出一种存储和转发方式插槽,以便我可以构建更接近其使用站点的对象,而不是作为成员变量.

我的基本问题是我有一个进程,它将在一个单独的线程上下载更新文件,并向任何感兴趣的人发送进度信号.信号基本上是:

typedef boost::signals2::signal<void (double)> DownloadProgress;
Run Code Online (Sandbox Code Playgroud)

假设progress下面提到的功能的实现符合这一点; 信号本身的性质并不是很重要(尽管我大部分时间都在使用仿函数).

信号已设置,代码调用如下:

Updater updater;
updater.onDownloadProgress(&progress);
updater.runDownloadTask();
Run Code Online (Sandbox Code Playgroud)

当你打电话时updater.runDownloadTask(),它会启动 UpdaterDownloadTask,启动HTTPRequest并返回一个 HTTPResponse.的HTTPResponse是,其与网络层相互作用并接收数据,并包含所述片DownloadProgress 的信号.有了这个,我的实现看起来有点像(自下而上 HTTPResponse,大大缩写为elide方法,不是特别说明):

class HTTPResponse
{
public:
  // this will be called for every "chunk" the underlying HTTP
  // library receives
  void processData(const char* data, size_t size)
  {
    // process the data and then send the progress signal
    // assume that currentSize_ and totalSize_ are properly set
    progressSignal_(currentSize_ * 100.0 / totalSize_);
  }

  void onDownloadProgress(const DownloadProgress::slot_type& slot)
  {
    progressSignal_.connect(slot);
  }

private:
  DownloadProgress progressSignal_;
};

class HTTPRequest
{
public:
  HTTPRequest() : response_(new HTTPResponse) { }

  void onDownloadProgress(const DownloadProgress::slot_type& slot)
  {
    response_->connect(slot);
  }

  boost::shared_ptr<HTTPResponse> perform()
  {
    // start the request, which operates on response_.
    return response_;
  }

private:
  boost::shared_ptr<HTTPResponse> response_;
};

class UpdaterDownloadTask : public AsyncTask
{
public:
  DownloadTask() : request_(new HTTPRequest) { }

  void onDownloadProgress(const DownloadProgress::slot_type& slot)
  {
    request_->connect(slot);
  }

  void run()
  {
    // set up the request_ and:
    request_>perform();
  }

private:
  boost::shared_ptr<HTTPRequest> request_;
};

class Updater
{
public:
  Updater() : downloadTask_(new UpdaterDownloadTask) { }
  void onDownloadProgress(const DownloadProgress::slot_type& slot)
  {
    downloadTask_->onDownloadProgress(slot);
  }

  void runDownloadTask() { downloadTask_.submit() }

private:
  boost::shared_ptr<UpdaterDownloadTask> downloadTask_;
};
Run Code Online (Sandbox Code Playgroud)

所以,我的Updater必须有一个实例UpdaterDownloadTask,它的实例是HTTPRequest,它有一个实例,HTTPResponse因为我必须将插槽连接从Updater(公共API入口点)转发到HTTPResponse (信号所属的位置) .

我宁愿这样实施UpdaterDownloadTask::run():

void run()
{
  HTTPRequest request;
  request.onDownloadProgress(slots_);

#if 0
  // The above is more or less equivalent to
  BOOST_FOREACH(const DownloadProgress::slot_type& slot, slots_)
  {
      request.onDownloadProgress(slot);
  }
#endif

  request.perform();
}
Run Code Online (Sandbox Code Playgroud)

这将在HTTPRequest级别具有类似的含义(因此我不必在执行请求之前构造HTTPResponse)并且总体上使用具有强RAII语义的更好的数据流.我之前尝试将slots_变量定义为向量:

std::vector<DownloadProgress::slot_type> slots_;
Run Code Online (Sandbox Code Playgroud)

但是,如果我强迫呼叫者打电话,我只能让这个工作 onDownloadProgress(boost::ref(slot));.

有没有人成功地完成了这项工作,或者对于如何存储和转发除了我正在做的事情之外有一个很好的建议?

Pat*_*ick 2

我认为将插槽存储在向量中应该可以正常工作。如果您想摆脱对的需要,可以从参数中boost::ref(...)删除(因为是可复制的)。&onDownloadProgressslot_type

或者,您可以将信号放在HTTPResponsefire 中,然后再触发信号 in HTTPRequest,这样做,您可以将所有插槽连接到信号 in HTTPRequest,然后一旦HTTPResponse创建,您就连接到响应信号onDownloadProgress(request.signalname)signalname你的客户的信号在哪里。

伪代码:

Request request;
request.onProgress(myProgressBarCallback);
    //calls: this.signal.connect(myProgressBarCallback);
request.go();
    //calls: Response response;
    //  and: response.onProgress(this.signal);
Run Code Online (Sandbox Code Playgroud)

我希望这有帮助。