2012-11-23 25 views
12

Sto provando a filtrare un vettore in modo che contenga solo un valore specifico.È possibile passare un parametro aggiuntivo a un predicato?

ad es. Assicurati che il vettore contenga solo elementi del valore "abc".

In questo momento, sto cercando di raggiungere questo con remove_copy_if.

C'è un modo per passare un parametro aggiuntivo a un predicato quando si utilizza uno degli algoritmi di std?

std::vector<std::string> first, second; 
first.push_back("abc"); 
first.push_back("abc"); 
first.push_back("def"); 
first.push_back("abd"); 
first.push_back("cde"); 
first.push_back("def"); 

std::remove_copy_if(first.begin(), first.end(), second.begin(), is_invalid); 

spero di passare la seguente funzione come un predicato ma sembra più probabile che questo sarebbe solo finire confrontando il valore corrente all'esame remove_copy_if e la successiva.

bool is_invalid(const std::string &str, const std::string &wanted) 
{ 
    return str.compare(wanted) != 0; 
} 

Ho la sensazione che probabilmente mi sto avvicinando a questo torto così ogni suggerimento sarebbe apprezzato!

Grazie

+0

Basta chiedersi: per cosa si utilizza un vettore con solo elementi identici? – Zane

+0

Ho cercato di rendere il mio esempio il più semplice possibile, quindi aveva senso :) Quello che ho fatto con questo è stato rimuovere elementi da un vettore che si adattano a un determinato modello (con espressioni regolari). – noko

risposta

16

Definire un funtore invece:

struct is_invalid 
{ 
    is_invalid(const std::string& a_wanted) : wanted(a_wanted) {} 
    std::string wanted; 
    bool operator()(const std::string& str) 
    { 
     return str.compare(wanted) != 0; 
    } 
}; 

std::remove_copy_if(first.begin(), 
        first.end(), 
        second.begin(), 
        is_invalid("abc")); 

o C++ 11 uso un lambda:

std::string wanted("abc"); 
std::remove_copy_if(first.begin(), first.end(), second.begin(), 
    [&wanted](const std::string& str) 
    { 
     return str.compare(wanted) != 0; 
    }); 

noti che l'output vector, second, deve avere elementi prima della chiamata a remove_copy_if():

// Create 'second' after population of 'first'. 
// 
std::vector<std::string> second(first.size()); 

std::string wanted = "abc"; 
int copied_items = 0; 
std::remove_copy_if(first.begin(), first.end(), second.begin(), 
    [&wanted, &copied_items](const std::string& str) -> bool 
    { 
     if (str.compare(wanted) != 0) return true; 
     copied_items++; 
     return false; 
    }); 
second.resize(copied_items); 

Come predicati Functor vengono copiati più sforzo è necessario per conservare le informazioni copied_items. Vedi Pass std algos predicates by reference in C++ per le soluzioni suggerite.

+0

Mi sembra di avere un errore su un "riferimento non definito" quando cerco di usare questa soluzione, qualche idea su cosa potrebbe accadere? – noko

+0

@noko, puoi pubblicare il tuo codice su ideone o simile? Nota che il compilatore deve supportare C++ 11 lambdas (in g ++ devi usare lo switch di compilatore '-std = C++ 0x'). – hmjd

+0

non importa, ho dimenticato di aggiungere un ClassName :: prima della funzione :( – noko

8

Fai funtore, o utilizzare std/boost::bind.

struct is_invalid 
{ 
public: 
    is_invalid(const std::string& w):wanted(w) { } 
    bool operator() (const std::string& str) 
    { 
     return str.compare(wanted) != 0; 
    } 
private: 
    std::string wanted; 
}; 

std::remove_copy_if(first.begin(), first.end(), second.begin(), is_invalid("abc")); 

Esempio con bind

bool is_invalid(const std::string &str, const std::string &wanted) 
{ 
    return str.compare(wanted) != 0; 
} 

std::remove_copy_if(first.begin(), first.end(), second.begin(), 
boost::bind(is_invalid, _1, "abc")); 
Problemi correlati