2011-11-29 12 views
9

Estoy tratando de eliminar elementos de un std::list y mantener algunas estadísticas de los elementos eliminados.Pasar std algos predicados por referencia en C++

Para hacerlo, utilizo la función remove_if de la lista y tengo un predicado. Me gustaría utilizar este predicado para recopilar estadísticas. Aquí está el código para el predicado:

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

Y aquí está el código para el algo:

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

Por desgracia, la afirmación es falsa porque el predicado se pasa por valor. ¿Hay alguna manera de forzar que se apruebe por referencia?

+1

No sé si se puede hacer directamente, pero podría usar un contenedor que contenga una referencia o un puntero al predicado real para obtener el efecto deseado. –

+0

Esa es una buena idea. Entonces podría crear una plantilla para envolver cualquier referencia de predicado ... Lo que me hace preguntarme si existe una plantilla así en stl o boost ... – Arthur

+0

@jules: ¡No dude en modificar su solución personalizada para su publicación! (Aunque estoy un poco irritado porque 'std :: tr1 :: ref' no hace el trabajo en C++ 03). ** Actualización: ** ¡Lo encontré! Editando ... –

Respuesta

15

pasar una envoltura de referencia, disponible en <functional>:

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

Si sólo tiene C++ 98/03, pero su compilador tiene TR1, puede utilizar <tr1/functional> y std::tr1::ref si hacer una pequeña enmienda a su predicado:

#include <tr1/functional> 

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

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

Si todo lo demás falla, t uando se puede hackear una solución manual con relativa facilidad:

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

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

Esto es de C++ TR1 pero una buena respuesta +1 –

2

Los funtores pasados ​​a los algoritmos pueden ser copiados dentro del algoritmo de un número indeterminado de veces, por lo que no se puede almacenar el estado directamente en el funtor. Puede, por otro lado, almacenar el estado fuera del functor, usando un puntero o referencia a alguna estructura de estado externo.

Cuestiones relacionadas