2011-11-29 10 views
9

Sto cercando di rimuovere elementi da un std::list e mantenere alcune statistiche di elementi eliminati.Passa std algos predicati per riferimento in C++

Per fare ciò, uso la funzione remove_if dall'elenco e ho un predicato. Mi piacerebbe utilizzare questo predicato per raccogliere statistiche. Ecco il codice per il predicato:

class TestPredicate 
    { 
    private: 
    int limit_; 

    public: 
    int sum; 
    int count; 
    TestPredicate(int limit) : limit_(limit), sum(0), count(0) {} 

    bool operator() (int value) 
    { 
     if (value >= limit_) 
     { 
     sum += value; 
     ++count;  // Part where I gather the stats 
     return true; 
     } 
     else 
     return false; 
    } 
    }; 

Ed ecco il codice per l'algo:

std::list <int> container; 
container.push_back(11); 
TestPredicate pred(10); 
container.remove_if(pred) 
assert(pred.count == 1); 

Purtroppo, l'affermazione è falsa, perché il predicato è passato per valore. C'è un modo per forzarlo a essere passato per riferimento?

+1

Non so se può essere eseguito direttamente, ma è possibile utilizzare un wrapper contenente un riferimento o un puntatore al predicato reale per ottenere l'effetto desiderato. –

+0

Questa è una buona idea. Quindi potrei creare un modello per racchiudere qualsiasi riferimento ai predicati ... Il che mi fa pensare se un modello di questo tipo esiste in stl o boost ... – Arthur

+0

@jules: Sentiti libero di modificare la tua versione del tuo messaggio! (Sono un po 'irritato dal fatto che 'std :: tr1 :: ref' non faccia il lavoro in C++ 03.) ** Aggiornamento: ** Trovato! Modifica ... –

risposta

15

passare un involucro di riferimento, disponibile da <functional>:

container.remove_if(std::ref(pred)); 

Se avete solo C++ 98/03, ma il compilatore ha TR1, è possibile utilizzare <tr1/functional> e std::tr1::ref se fare un piccolo modifica il tuo predicato:

#include <tr1/functional> 

class TestPredicate : public std::unary_function<int, bool> 
{     //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
    // ... 
} 

container.remove_if(std::tr1::ref(pred)); 

Se tutto il resto fallisce, t uando si può incidere su una soluzione manuale con relativa facilità:

struct predref 
{ 
    TestPredicate & p; 
    bool operator()(int n) { return p(n); } 
    predref(TestPredicate & r) : p(r) { } 
}; 

container.remove_if(predref(pred)); 
+0

Questo è da C++ TR1 ma una buona risposta +1 –

2

I funtori passati gli algoritmi possono essere copiati all'interno l'algoritmo di un numero indeterminato di volte, quindi non è possibile memorizzare lo stato direttamente nel funtore. È possibile, d'altra parte, memorizzare lo stato al di fuori del functor, utilizzando un puntatore o un riferimento a una struttura di stato esterna.