2012-01-20 14 views
5

Ho un problema in cui sto avendo per creare un'istanza di istanze di oggetti prima di quanto mi piacerebbe farlo perché mi serve per collegare il segnale slot attraverso alcune proprietà profonda, e mi piacerebbe trovare una modo di memorizzare e inoltrare gli slot in modo che io possa costruire oggetti più vicini al loro sito di utilizzo, invece di farlo come variabili membro.Come posso memorizzare e inoltrare gli slot usando boost :: signals2?

Il mio problema di base è che ho un processo che scaricherà un file di aggiornamento su un thread separato e invia un segnale di avanzamento a chiunque sia interessato a . Il segnale è essenzialmente:

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

supponga che l'implementazione della funzione progress menzionato sotto conforme a questa; la natura del segnale stesso non è molto importante (sebbene io stia usando per la maggior parte i funtori).

Il segnale viene impostato e il codice si chiama qualcosa di simile:

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

Quando si chiama updater.runDownloadTask(), inizierà la UpdaterDownloadTask, che inizia un HTTPRequest e restituisce un HTTPResponse. Il HTTPResponse è il pezzo che interagisce con il livello di rete e riceve i dati e contiene il segnale DownloadProgress . Con questo, la mia implementazione sembra un po 'come (bottom-up da HTTPResponse, pesantemente abbreviato per elidere i metodi che non sono particolarmente illustrativo):

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_; 
}; 

Quindi, la mia Updater deve avere un'istanza di UpdaterDownloadTask che è sempre intorno, che dispone di un'istanza di HTTPRequest, che ha un un'istanza di HTTPResponse -proprio perché devo trasmettere slot connessione dal Updater (punto di ingresso API pubblica) per HTTPResponse (dove il segnale frazione).

avrei preferito attuare UpdaterDownloadTask::run() modo:

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

Ciò avrebbe conseguenze analoghe a livello HTTPRequest (quindi non dover costruire la HTTPResponse finché non eseguire la richiesta) e make complessiva per un flusso di dati migliore con una forte semantica di RAII. Ho precedenza cercato di definire la variabile slots_ come vettore:

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

Eppure posso solo ottenere questo al lavoro se forzo i chiamanti a chiamare onDownloadProgress(boost::ref(slot));.

Qualcuno ha fatto questo con successo, o ha un buon suggerimento su come memorizzare e inoltrare diverso da quello che sto facendo?

risposta

2

Penso che la memorizzazione degli slot in un vettore dovrebbe funzionare correttamente.Se si desidera eliminare la necessità di boost::ref(...), è possibile rimuovere il parametro & dal parametro onDownloadProgress (poiché è possibile copiare slot_type).

In alternativa, si potrebbe avere il segnale all'interno HTTPResponse fuoco e nel fuoco sua volta un segnale in HTTPRequest, facendo questo, si potrebbe collegare tutti gli slot al segnale in HTTPRequest, poi una volta creato il HTTPResponse, si collega alla risposta segnale onDownloadProgress(request.signalname). Dove signalname è il segnale del tuo cliente.

pseudocodice:

Request request; 
request.onProgress(myProgressBarCallback); 
    //calls: this.signal.connect(myProgressBarCallback); 
request.go(); 
    //calls: Response response; 
    // and: response.onProgress(this.signal); 

Mi auguro che aiuta.

+0

Ho provato alcune cose con un vettore in precedenza, ma potrebbe essere stato un errore da parte mia. Penso tu abbia ragione. –

Problemi correlati