2008-11-05 22 views
14

que tienen alguna función para encontrar un valor:¿Cómo puedo negar un functor en C++ (STL)?

struct FindPredicate 
{ 

    FindPredicate(const SomeType& t) : _t(t) { 
    } 
    bool operator()(SomeType& t) { 
     return t == _t; 
    } 

private: 
    const SomeType& _t; 
}; 

bool ContainsValue(std::vector<SomeType>& v, SomeType& valueToFind) { 
    return find_if(v.begin(), v.end(), FindPredicate(valueToFind)) != v.end(); 
} 

Ahora me gustaría escribir una función que comprueba si todos los miembros de un vector satisfacen ese predicado:

bool AllSatisfy(std::vector<SomeType>& v) { 
    /* ... */ 
} 

Una solución es utilizar el algoritmo std::count_if.

¿Alguien sabe una solución que implica la negación del predicado?

Respuesta

20

La mejor solución es usar el STL functional library. Al derivar su predicado de unary_function<SomeType, bool>, entonces podrá usar la función not1, que hace exactamente lo que necesita (es decir, negando un predicado unario).

Aquí es cómo se puede hacer eso:

struct FindPredicate : public unary_function<SomeType, bool> 
{ 
    FindPredicate(const SomeType& t) : _t(t) {} 

    bool operator()(const SomeType& t) const { 
     return t == _t; 
    } 

private: 
    const SomeType& _t; 
}; 

bool AllSatisfy(std::vector<SomeType>& v, SomeType& valueToFind) 
{ 
    return find_if(v.begin(), 
        v.end(), 
        not1(FindPredicate(valueToFind))) == v.end(); 
} 

Si quieren rodar su propia solución (que es, en mi humilde opinión, no es la mejor opción ...), así, se podría escribir otro predicado que es la negación de la primera:

struct NotFindPredicate 
{ 

    NotFindPredicate(const SomeType& t) : _t(t) { 
    } 
    bool operator()(SomeType& t) { 
     return t != _t; 
    } 

private: 
    const SomeType& _t; 
}; 

bool AllSatisfy(std::vector<SomeType>& v) { 
    return find_if(v.begin(), 
        v.end(), 
        NotFindPredicate(valueToFind)) == v.end(); 
} 

O se podría hacer mejor y escribir un negador plantilla funtor, como:

template <class Functor> 
struct Not 
{ 
    Not(Functor & f) : func(f) {} 

    template <typename ArgType> 
    bool operator()(ArgType & arg) { return ! func(arg); } 

    private: 
    Functor & func; 
}; 

que se puede utilizar de la siguiente manera:

bool AllSatisfy(std::vector<SomeType>& v, SomeType& valueToFind) 
{ 
    FindPredicate f(valueToFind); 
    return find_if(v.begin(), v.end(), Not<FindPredicate>(f)) == v.end(); 
} 

Por supuesto, esta última solución es mejor porque se puede volver a utilizar la estructura No con cada funtor que desea.

+0

Y entonces se podría agregar una función de plantilla cuña como la gente de la SGI hicieron para devolver un objeto no sin tener que especificar su tipo. – xtofl

7

Vea el funcionador de la biblioteca std not1, devuelve un functor que es lógico, no de lo que sea que devuelva el functor que le proporcione.

Usted debe ser capaz de hacer algo como:

bool AllSatisfy(std::vector<SomeType>& v, SomeType& valueToFind) { 
    return find_if(v.begin(), v.end(), not1(FindPredicate(valueToFind))) != v.end(); 
} 
2

La primera vez que utilicé not1 Me preguntaba por qué no se llama simplemente not.

La respuesta me sorprendió un poco (ver comentario).

+0

Aparentemente 'no 'es una representación alternativa reservada del símbolo'! '(Sección 2.11.2 en el estándar [lex.key]) – Motti

+2

Otra razón es que distingue la negación de un predicado unario (not1) de la negación de un predicado binario (not2). –

0

Al usarlo, no necesita el Functor FindPredicate, ya que en el ejemplo solo está probando la igualdad.

bool all_equal(std::vector<SomeType>& v, SomeType& valueToFind) 
{ 
    return v.end() == find_if(v.begin(), v.end(), std::bind1st (equal_to(), valueToFind)); 
} 

bool all_not_equal(std::vector<SomeType>& v, SomeType &valueToFind) { 
{ 
    return v.end() == find_if(v.begin(), v.end(), std::bind1st (not_equal_to(), valueToFind)); 
} 

Y usted podría simplemente hacer de esto una plantilla por sí mismo.

template< typename InputIterator , typename Predicate > 
bool test_all(InputIterator first, InputIterator last, Predicate pred) 
{ 
    return last == find_if(first, last, pred); 
} 

test_all(v.begin(), v.end(), std::bind1st(not_equals_to_(value)));