2015-12-17 7 views
5

das folgende Szenario vor:von UnaryPredicate in Lösch-remove Idiom Mit Negation

bool is_odd(int i) 
{ 
    return (i % 2) != 0; 
} 
int main() 
{ 
    // ignore the method of vector initialization below. 
    // assume C++11 is not to be used. 
    std::vector<int> v1 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 
    std::vector<int> v2 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 

    // removes all odd numbers, OK 
    v1.erase(std::remove_if(v1.begin(), v1.end(), is_odd), v1.end()); 

    // remove all even numbers 
    v2.erase(std::remove_if(v2.begin(), v2.end(), ???), v2.end()); 
} 

Kann ich die gleichen is_odd() UnaryPredicate verwenden, auch Zahlen zu entfernen, wie in der letzten Zeile der main() erwartet. Oder werde ich muss unbedingt ein is_even() schreiben, obwohl es nichts sein, aber:

bool is_even(int i) 
{ 
    !is_odd(i); 
} 
+1

Wenn Sie ++ haben C 11, eine Lambda ist am einfachsten: '[] (int i) {return is_odd (i); } ', und ich würde klarer behaupten als etwas wie' not1'. – BoBTFish

+0

Entschuldigung bemerkte die = vor den geschweiften Klammern –

+0

@HumamHelfawi: selbst mit dem '=' der obige Code erfordert C++ 11! Es gibt keinen direkten Weg, einen 'std :: vector' (oder einen der anderen Standard-Bibliothekscontainer) mit einer Sequenz von Elementen in C++ vor C++ 11 zu initialisieren. Der Weg dazu wäre die Erstellung eines Arrays und dann die Verwendung von Iteratoren für das Array mit dem Konstrukt des Containers. –

Antwort

9

Kontrolle der std::not1 Funktion. es macht was du willst.

v2.erase(std::remove_if(v2.begin(), v2.end(), std::not1(std::ptr_fun(is_odd))), v2.end()); 

Live example

Wie auch immer, wenn es nach mir ist plus C 11 ++ ist verfügbar Ich würde prefere:

v2.erase(std::remove_if(v2.begin(), v2.end(), [&](auto/* or the type */ const& item){return !is_odd(item);}), v2.end()); 

denn soweit ich mich erinnere std::not1 hilfreich war, bevor lambda war verfügbar.

5

Sie können std::not1 verwenden. Leider erfordert std::not1 ein Funktionsobjektargument mit verschachtelten Typen argument_type und . Das heißt, es kann nicht direkt verwendet werden. Vielmehr ist es notwendig, die Verwendung mit std::ptr_fun zu kombinieren, wenn die negator mit einer normalen Funktion:

v2.erase(std::remove_if(v2.begin(), v2.end(), std::not1(std::ptr_fun(is_odd))), v2.end()); 

Auf der letzten Sitzung des Ausschusses std::not_fn wurde aus dem Library Fundamentals TS 2 in den Arbeitsentwurf bewegt. Das heißt, es gibt Hoffnung, dass es mit C++ 17 ein besseres Angebot für einen generischen Negator gibt.

Im Allgemeinen stoppt der Spaß, wenn Sie eine der std::*_fun Funktionen verwenden müssen. Wie andere haben darauf hingewiesen, kann es sinnvoll sein, anstelle einer Lambda zu verwenden:

v2.erase(std::remove_if(v2.begin(), v2.end(), [](auto&& x){ return !::is_odd(x); }), v2.end()); 

Die Verwendung einer Lambda-Funktion oder ein Funktionsobjekt mit einer inline Funktion Call-Betreiber auch den Vorteil hat, dass der Compiler eine einfachere Zeit hat Inlining des Codes.

Selbstverständlich, wenn Sie verwenden müssen, C++ vor C++ 11 der std::not1/std::ptr_fun Ansatz ist die einfachste für den sofortigen Einsatz eine die Verwendung einer Lambda-Funktion ist auch gar nicht möglich. In diesem Fall können Sie eine einfache Funktion Objekt erstellen inlining zu unterstützen:

struct not_odd { 
    template <typename T> 
    bool operator()(T const& value) const { return !::odd(value); } 
}; 
// ... 
v2.erase(std::remove_if(v2.begin(), v2.end(), not_odd()), v2.end()); 
+0

"der Spaß hört auf, wenn Sie irgendwelche verwenden müssen die Funktionen von std :: * _ fun ". Ist es nur der Spaß, oder gibt es auch einen technischen/praktischen Nachteil? – CinCout

+0

@HappyCoder: Der Kommentar ist etwas ironisch, aber es basiert auf der Erfahrung, dass die Notwendigkeit, 'std :: ptr_fun' zu verwenden, leicht vergessen wird (wie die andere Antwort gezeigt hat) und mehr, dass das richtige verwendet Version der 'std :: mem * _fun 'Version mit Memberfunktionszeiger ist nicht offensichtlich. 'std :: mem_fn' löst das Problem einigermaßen gut für Memberfunktionszeiger. –