2015-03-24 7 views
6

Derzeit, wenn Sie ein Prädikat negieren möchten, müssen Sie eine std::<algorithm>_if_not Variante oder ein Lambda verwenden. Aber im Interesse der Wissenschaftler Ich möchte wissen, ob dies möglich ist:Wie verwenden Sie std :: not1 und std :: not2?

std::string s("hello"); 
std::find_if(s.begin(), s.end(), std::not1(::ispunct)); 

Ohne meine eigene Funktion Objekt zu schreiben, wie dieser Code funktioniert?

+0

Mit der Bibliothek Grundlagen v2 TS, 'std :: not_fn (:: ispunct)'. Beachten Sie jedoch, dass die Zeichen in "unsigned char" konvertiert werden müssen, bevor sie in "ispunct" übergeben werden, damit dieser Aufruf für eine beliebige Zeichenfolge sicher ist. – chris

Antwort

8

Denken Sie daran, dass die richtige Art und Weise char s die Zeichenklassifikationsfunktionen passieren (zusammen mit toupper und tolower), die aus der C-Standard-Bibliothek kamen ist, es zuerst zu unsigned char und dann zu int zu konvertieren.

Mit std::ref und reference_wrapper ist dies leicht und falsch. Mit std::function<bool(int)> oder std::function<bool(char)> sind schwerer, und auch falsch. In all diesen Fällen wird char in der Zeichenfolge direkt in int konvertiert, was nicht der richtige Weg ist.

Wenn Sie darauf bestehen, nicht einen Lambda verwenden, dann

std::find_if(s.begin(), s.end(), std::not1(std::function<bool(unsigned char)>(::ispunct))); 

ist eine richtige Weg, es zu tun. Ansonsten

std::find_if(s.begin(), s.end(), [](unsigned char c) { return !ispunct(c); }); 

ist einfacher zu verstehen - und kürzer.

+0

Können Sie Ihren ersten Satz erklären oder Referenzen geben? – Pradhan

+1

@Pradhan Diese Funktionen sind im C-Standard definiert. WG14 N1570 §7.4 - "Die Kopfzeile' 'deklariert mehrere Funktionen, die zum Klassifizieren und Abbilden von Zeichen nützlich sind. In allen Fällen ist das Argument ein 'int', dessen Wert als 'Zeichen ohne Vorzeichen' oder gleich dem Wert dargestellt werden kann des Makros 'EOF'. Wenn das Argument einen anderen Wert hat, ist das Verhalten nicht definiert." –

4

Der unäre Prädikat-Typ muss einen Mitgliedstyp argument_type definieren, der in den Prädikatparametertyp konvertierbar ist.

Der leichteste Weg ::ispunct zu wickeln ist std::reference_wrapper zu verwenden:

std::find_if(s.begin(), s.end(), std::not1(std::ref(::ispunct))); 
              ^^^^^^^^ 
-1

Einer von Ansätzen ist std::reference_wrapper zu verwenden. Hier ist ein Demonstrationsprogramm

#include <iostream> 
#include <functional> 
#include <string> 
#include <cctype> 
#include <algorithm> 

int main() 
{ 
    std::string s("...hello"); 

    auto it = std::find_if(s.begin(), s.end(), std::not1(std::ref(::ispunct))); 

    std::cout << *it << std::endl; 

    return 0; 
} 

Der Ausgang ist

h 
Verwandte Themen