2015-03-24 9 views
6

Attualmente se si desidera annullare un predicato, è necessario utilizzare una variante std::<algorithm>_if_not o una lambda. Ma per il bene degli accademici Voglio sapere se questo è possibile:Come si usa std :: not1 e std :: not2?

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

senza scrivere il mio oggetto funzione, come fare questo lavoro di codice?

+0

Con la libreria Fondamentali v2 TS, 'std :: not_fn (:: ispunct)'. Si noti, tuttavia, che affinché questa chiamata sia sicura per qualsiasi stringa, i caratteri devono essere convertiti in 'char unsigned 'prima di essere passati in' ispunct'. – chris

risposta

8

Ricordate che il modo corretto di passare char s per le funzioni di classificazione dei caratteri (insieme a toupper e tolower) che è venuto dalla libreria standard C è per convertirlo prima a unsigned char e poi a int.

Utilizzare std::ref e uno reference_wrapper per questo è leggero e sbagliato. L'utilizzo di std::function<bool(int)> o std::function<bool(char)> è più pesante e anche sbagliato. In tutti questi casi, lo char nella stringa viene convertito direttamente in int, che non è il modo giusto per farlo.

Se ti ostini a non usare un lambda, quindi

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

è un modo giusto per farlo. Altrimenti

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

è più facile da capire - e più breve.

+0

Puoi spiegare o fornire riferimenti per la tua prima frase? – Pradhan

+1

@Pradhan Queste funzioni sono definite nello standard C. WG14 N1570 §7.4 - "L'intestazione' 'dichiara diverse funzioni utili per classificare e mappare caratteri. In tutti i casi l'argomento è un' int', il cui valore deve essere rappresentabile come un 'carattere senza segno 'o deve essere uguale al valore della macro 'EOF'. Se l'argomento ha qualche altro valore, il comportamento non è definito." –

4

Il tipo di predicato unario deve definire un tipo di membro, argument_type, convertibile nel tipo di parametro del predicato.

Il modo più leggero per avvolgere ::ispunct è quello di utilizzare std::reference_wrapper:

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

Uno degli approcci è quello di utilizzare std::reference_wrapper. Ecco un programma dimostrativo

#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; 
} 

L'uscita è

h 
Problemi correlati