2012-01-20 9 views
5

オブジェクトのインスタンスをインスタンス化する必要があるという問題があります。信号を接続する必要があるため、より早くオブジェクトをインスタンス化する必要があります。 スロットを所有しています。私はスロットを格納して転送して、メンバー変数の代わりに に近いオブジェクトを使用サイトに構築できるようにします。boost :: signals2を使ってスロットを格納して転送するにはどうしたらいいですか?

私の基本的な問題は、別のスレッドにアップデート ファイルをダウンロードし、進捗信号を に送信するプロセスがあることです。信号は、本質的に:

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

progress関数の実装は、以下 これに準拠を述べているものとします。信号そのものの性質はそれほど重要ではありません(私はほとんどの場合、ファンクターを使用していますが)。 重要です。

信号がセットされ、コードは次のようなものと呼ばれている:あなたはupdater.runDownloadTask()を呼び出すと

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

、それはHTTPRequestを開始し、 HTTPResponseを返す UpdaterDownloadTaskを、開始します。 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_; 
}; 

、私のアップデータですUpdaterDownloadTaskのインスタンスを持つことがあります 常に周りに、私は(信号が所属)HTTPResponseUpdaterからスロット 接続(パブリックAPIエントリポイント)を転送する必要があるためHTTPResponse -JUSTの インスタンスを有するHTTPRequestのインスタンスを有します。

私はむしろそうのようなUpdaterDownloadTask::run()を実装します:これは、HTTPRequestのレベルでの同様の意味合いを持っているでしょう

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(); 
} 

と全体的なメイクを(ので、私は、要求を実行するまでHTTPResponseはを構築する必要はありません )強力なRAIIセマンティクスを持つより良いデータフローを実現します。私は は以前にベクトルとしてslots_変数を定義しようとしました:

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

をしかし、私は onDownloadProgress(boost::ref(slot));を呼び出すために発信者を強制する場合、私はこれだけ仕事を得ることができます。

誰でもこれをうまくやったことがありますか、または私がやっていること以外に保存して転送する方法については、良い提案がありますか?

答えて

2

私は、ベクトルにスロットを格納することはOKです。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); 

私はそれが役に立てば幸い。

+0

以前はベクターで試したことがありましたが、私のところはエラーだったかもしれません。あなたが正しいと思います。 –

関連する問題