14 Stimmen

Wie kann ich einen Funktor in C++ (STL) negieren?

Ich habe eine Funktion, um einen Wert zu finden:

struct FindPredicate
{

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

private:
    const SomeType& _t;
};

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

Jetzt möchte ich eine Funktion schreiben, die überprüft, ob alle Elemente eines Vektors dieses Prädikat erfüllen:

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

Eine Lösung besteht darin, den Algorithmus std::count_if zu verwenden.

Weiß jemand eine Lösung, die das Prädikat verneint?

21voto

Luc Touraille Punkte 76149

Die beste Lösung besteht darin, die STL functionale Bibliothek zu verwenden. Indem Sie Ihr Prädikat von unary_function ableiten, können Sie dann die Funktion not1 verwenden, die genau das tut, was Sie brauchen (d.h. ein unäres Prädikat negiert).

So könnten Sie das machen :

struct FindPredicate : public unary_function
{
    FindPredicate(const SomeType& t) : _t(t) {}

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

private:
    const SomeType& _t;
};

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

Wenn Sie Ihre eigene Lösung erstellen möchten (was meiner Meinung nach nicht die beste Option ist...), könnten Sie einfach ein weiteres Prädikat schreiben, das die Negation des ersten ist :

struct NotFindPredicate
{

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

private:
    const SomeType& _t;
};

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

Oder Sie könnten es noch besser machen und einen Template-Funktornegator schreiben, wie :

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

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

  private:
    Functor & func;
};

den Sie wie folgt verwenden könnten :

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

Natürlich ist die letztere Lösung besser, weil Sie die Not-Struktur mit jedem gewünschten Funktor wiederverwenden können.

7voto

Greg Rogers Punkte 34400

Siehe den std-Bibliotheks-Funktor not1, er gibt einen Funktor zurück, der das logische Nicht von dem zurückgibt, was auch immer der Funktor, den Sie ihm geben, zurückgeben würde.

Sie sollten in der Lage sein, etwas ähnliches zu tun:

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

2voto

Motti Punkte 104854

Das erste Mal, dass ich not1 benutzt habe, habe ich mich gefragt, warum es nicht einfach not genannt wurde.

Die Antwort hat mich ein wenig überrascht (siehe Kommentar).

0voto

Sanjaya R Punkte 5886

Da du es verwendest, brauchst du den FindPredicate Funktor nicht, da du im Beispiel nur die Gleichheit testest.

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

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

Und du könntest das einfach selbst zu einer Vorlage machen.

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X