【问题标题】:How can I store and forward slots using boost::signals2?如何使用 boost::signals2 存储和转发插槽?
【发布时间】:2012-01-20 04:43:03
【问题描述】:

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

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

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

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

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

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

当你调用updater.runDownloadTask()时,它会启动 UpdaterDownloadTask,它开始一个 HTTPRequest 并返回一个 HTTPResponseHTTPResponse 是与 网络层并接收数据并包含DownloadProgress 信号。有了这个,我的实现看起来有点像(自下而上 HTTPResponse,严重缩写为省略不属于的方法 特别说明):

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));.

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

【问题讨论】:

    标签: c++ boost-signals2


    【解决方案1】:

    我认为将插槽存储在向量中应该可以。如果您想摆脱对boost::ref(...) 的需求,您可以从onDownloadProgress 参数中删除&amp;(因为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);
    

    希望对你有帮助。

    【讨论】:

    • 我之前曾尝试过使用矢量进行一些操作,但这可能是我的错误。我认为你是对的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-22
    • 2012-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多