深い所有権を介してシグナルスロットを接続する必要があるため、オブジェクトのインスタンスを希望するよりも早くインスタンス化する必要があるという問題があります。これにより、メンバー変数としてではなく、使用場所に近いオブジェクトを構築できます。
私の基本的な問題は、別のスレッドで更新ファイルをダウンロードし、興味のある人に進行状況信号を送信するプロセスがあることです。信号は本質的に次のとおりです。
typedef boost::signals2::signal<void (double)> DownloadProgress;
以下の関数の実装はprogress
これに従うものとします。シグナル自体の性質はそれほど重要ではありません (ただし、ほとんどの部分でファンクターを使用しています)。
シグナルが設定され、コードは次のように呼び出されます。
Updater updater;
updater.onDownloadProgress(&progress);
updater.runDownloadTask();
を呼び出すとupdater.runDownloadTask()
、 が開始され
UpdaterDownloadTask
、 が開始されて がHTTPRequest
返されます
HTTPResponse
。はHTTPResponse
、ネットワーク層とやり取りし、データを受信して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));
.
誰かがこれを成功させましたか、または私がしていること以外に保存および転送する方法について良い提案がありますか?