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

时间:2012-01-20 04:43:04

标签: c++ boost-signals2

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

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

typedef boost::signals2::signal<void (double)> DownloadProgress;

假设提到了progress函数的实现 以下符合此;信号本身的性质不是很好 很重要(虽然我大部分时间都在使用仿函数)。

设置信号并调用代码如下:

Updater updater;
updater.onDownloadProgress(&progress);
updater.runDownloadTask();

当你致电updater.runDownloadTask()时,它会启动。{ UpdaterDownloadTask,它启动HTTPRequest并返回 HTTPResponseHTTPResponse是与...交互的部分 网络层并接收数据并包含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_;
};

因此,我的更新程序必须有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();
}

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

std::vector<DownloadProgress::slot_type> slots_;

然而,如果我强迫来电者打电话,我只能让这个工作 onDownloadProgress(boost::ref(slot));

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

1 个答案:

答案 0 :(得分:2)

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

或者,您可以让HTTPResponse内的信号触发,然后在HTTPRequest内发出信号,这样做,您可以将所有插槽连接到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);

我希望有所帮助。