2008-11-05 6 views
14

Ich habe eine Funktion, um einen Wert zu finden:Wie kann ich einen Funktor in C++ (STL) negieren?

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

Nun würde Ich mag eine Funktion schreiben, die alle Mitglieder eines Vektors überprüft, ob dieses Prädikat erfüllen:

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

One-Lösung zu verwenden ist der std::count_if Algorithmus.

Kennt jemand eine Lösung, die das Prädikat negiert?

Antwort

20

Die beste Lösung ist die STL functional library. Wenn Sie Ihr Prädikat von unary_function<SomeType, bool> ableiten, können Sie dann die Funktion not1 verwenden, die genau das tut, was Sie benötigen (d. H. Ein unäres Prädikat negieren).

Hier ist, wie Sie tun können, dass:

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

Wenn Sie Ihre eigene Lösung rollen wollen (das ist, meiner Meinung nach, nicht die beste Option ...), na ja, man könnte schreiben ein weiteres Prädikat, das die Negation der erste ist:

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

Oder man könnte es besser machen und eine Vorlage Funktors negator schreiben, wie:

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

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

    private: 
    Functor & func; 
}; 

, die Sie wie folgt verwenden:

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

Natürlich ist die letztere Lösung ist besser, weil man die Nicht Struktur mit jedem Funktor Sie wiederverwenden können.

+0

Und dann könnten Sie eine Shim-Template-Funktion hinzufügen, wie die sgi Leute ohne ein Nicht Objekt zurückgeben taten Typ es ist zu spezifizieren. – xtofl

7

Sehen Sie die std-Bibliothek Funktor not1, gibt es einen Funktor, der das logische nicht von was auch immer der Funktor ist, den Sie geben, würde zurückgeben.

Sie sollten in der Lage sein, so etwas zu tun:

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

Das erste Mal habe ich not1 Ich fragte mich, warum es nicht einfach not genannt wurde.

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

+0

Anscheinend ist 'not 'eine reservierte alternative Darstellung des Symbols'! '(Abschnitt 2.11.2 im Standard [lex.key]) – Motti

+2

Ein weiterer Grund ist, dass es die Negation eines unären Prädikats (not1) von der Negation von unterscheidet ein binäres Prädikat (not2). –

0

Wie Sie es verwenden, benötigen Sie den FindPredicate-Funktor nicht, da Sie in dem Beispiel nur Gleichheit testen.

Und Sie könnten dies nur eine Vorlage für sich 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)));