Mam problem polegający na tym, że muszę wcześniej utworzyć instancje obiektów , ponieważ muszę podłączyć sygnały przez niektóre głębokie prawa własności i chciałbym wymyślić sposób zapisywania i przesyłania szczelin, aby móc budować obiekty bliżej na swojej stronie użycia, zamiast robić to jako zmienne członkowskie.Jak mogę przechowywać i przekazywać gniazda za pomocą metody boost :: signals2?
Mój podstawowy problem polega na tym, że mam proces, który pobiera plik aktualizacji w oddzielnym wątku i wysyła sygnał postępu do każdego zainteresowanego, który jest interesujący . Sygnał jest zasadniczo:
typedef boost::signals2::signal<void (double)> DownloadProgress;
Załóżmy, że realizacja funkcji progress
wspomniano poniżej jest zgodny z tym; charakter samego sygnału nie jest bardzo ważny (chociaż w większości korzystam z funktorów).
Sygnał jest ustawiony i kod nazywany jest coś takiego:
Updater updater;
updater.onDownloadProgress(&progress);
updater.runDownloadTask();
Po wywołaniu updater.runDownloadTask()
, rozpocznie się UpdaterDownloadTask
, który uruchamia HTTPRequest
i zwraca HTTPResponse
. HTTPResponse
to element, który wchodzi w interakcję z warstwą sieciową i odbiera dane oraz zawiera sygnał o numerze. Z tym, moja realizacja wygląda nieco jak (bottom-up z HTTPResponse
, mocno skrócona do abstrahować metod, które nie są szczególnie ilustracyjne):
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_;
};
Więc moje Updater musi mieć instancję UpdaterDownloadTask
który jest zawsze wokół, który ma wystąpienie HTTPRequest
, która ma wystąpienie HTTPResponse
-Tylko dlatego, że mam do przekazania gniazda połączenie z Updater
(publicznego API punkt odbioru) do HTTPResponse
(gdzie należy sygnał).
wolałbym wdrożyć UpdaterDownloadTask::run()
tak:
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();
}
będzie to mieć podobne skutki na poziomie HTTPRequest (tak nie muszą skonstruować httpResponse dopóki nie wykona żądanie) i ogólną markę dla lepszego przepływu danych z silną semantyką RAII. Mam wcześniej próbował definiując zmienną slots_
jako wektor:
std::vector<DownloadProgress::slot_type> slots_;
Jeszcze mogę to tylko do pracy, jeśli zmusić zadzwonienie onDownloadProgress(boost::ref(slot));
.
Czy ktoś zrobił to z powodzeniem lub miał dobrą sugestię, jak przechowywać i przesyłać dalej niż to, co robię?
Próbowałem wcześniej pewnych rzeczy z wektorem, ale mógł to być błąd z mojej strony. Myślę, że masz rację. –