2010-04-16 8 views
6

Sono confuso sull'interfaccia di std::find. Perché non prende un oggetto Compare che indica come confrontare due oggetti?Come std :: find utilizzando un oggetto Confronta?

Se potessi passare un oggetto Compare ho potuto fare il seguente lavoro di codice, in cui vorrei confrontare con il valore, invece di confrontare i valori puntatore direttamente:

typedef std::vector<std::string*> Vec; 
Vec vec; 
std::string* s1 = new std::string("foo"); 
std::string* s2 = new std::string("foo"); 
vec.push_back(s1); 
Vec::const_iterator found = std::find(vec.begin(), vec.end(), s2); 
// not found, obviously, because I can't tell it to compare by value 
delete s1; 
delete s2; 

è la seguente il metodo consigliato per farlo?

template<class T> 
struct MyEqualsByVal { 
    const T& x_; 
    MyEqualsByVal(const T& x) : x_(x) {} 
    bool operator()(const T& y) const { 
    return *x_ == *y; 
    } 
}; 
// ... 
vec.push_back(s1); 
Vec::const_iterator found = 
    std::find_if(vec.begin(), vec.end(), 
       MyEqualsByVal<std::string*>(s2)); // OK, will find "foo" 

risposta

6

find non può essere sovraccaricato per prendere un predicato unario invece di un valore, perché è un parametro del modello non vincolato. Quindi, se hai chiamato find(first, last, my_predicate), ci sarebbe una potenziale ambiguità se vuoi che il predicato sia valutato su ciascun membro dell'intervallo, o se vuoi trovare un membro dell'intervallo uguale al predicato stesso (potrebbe essere un intervallo di predicati, per tutti i progettisti delle librerie standard conosciuti o interessati, oppure il value_type dell'iteratore potrebbe essere convertibile sia per il tipo di predicato, sia per il suo argument_type). Da qui la necessità di find_if di andare sotto un nome separato.

find potrebbe essere stato sovraccaricato per prendere un predicato binario opzionale, oltre al valore cercato. Ma catturare i valori nei funtori, come hai fatto, è una tecnica così standard che non penso che sarebbe un grande guadagno: non è certamente mai necessario dato che puoi sempre ottenere lo stesso risultato con find_if.

Se hai la find si voleva, saresti ancora deve scrivere un funtore (o usare boost), dal momento che <functional> non contiene nulla per dereference un puntatore. Tuttavia, il tuo functor sarebbe un po 'più semplice come un predicato binario, oppure potresti usare un puntatore a funzione, quindi sarebbe un guadagno modesto. Quindi non so perché questo non è fornito. Dato il fiasco copy_if non sono sicuro che ci sia molto valore nell'assumere che ci siano sempre buone ragioni per gli algoritmi che non sono disponibili :-)

+0

Grazie! Per curiosità, cosa c'è di sbagliato in 'copy_if'? – Frank

+1

@dehmann: l'unica cosa sbagliata è che non è nello standard. È stato tralasciato essenzialmente a causa di un incidente di montaggio. –

2

Dal momento che il T è un puntatore, si può anche memorizzare una copia del puntatore nella oggetto funzione.

Oltre a questo, è così che è fatto e non c'è molto di più.

Per inciso, non è una buona idea archiviare puntatori nudi in un contenitore, a meno che non si sia estremamente cauti nell'assicurare un'eccezione di sicurezza, che è quasi sempre più fastidiosa di quanto valga.

+0

E ... ho completamente perso la prima metà della domanda ... oops. Però, la risposta di Steve Jessop è migliore di quanto avrei potuto spiegarlo comunque. –

0

Questo è esattamente ciò che è find_if - prende un predicato che viene chiamato per confrontare gli elementi.

Problemi correlati