2012-11-23 24 views
12

Próbuję filtrować wektor, aby zawierał tylko określoną wartość.Czy można przekazać dodatkowy parametr do predykatu?

np. Upewnij się, że wektor zawiera tylko elementy o wartości "abc".

W tej chwili staram się to osiągnąć z remove_copy_if.

Czy istnieje jakiś sposób przekazania dodatkowego parametru do predykatu podczas korzystania z jednego z algorytmów 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); 

mam nadzieję przekazać następującą funkcję jako orzecznik, ale wydaje się bardziej prawdopodobne, że będzie to po prostu skończyć porównując aktualną wartość badane przez remove_copy_if a następnym.

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

Mam wrażenie, ja prawdopodobnie zbliża się to źle więc wszelkie sugestie będą mile widziane!

Dzięki

+0

Po prostu zastanawiam się - do czego służy wektor z identycznymi elementami? – Zane

+0

Próbowałem uczynić mój przykład tak prostym, jak to tylko możliwe, więc miało to sens :) Zrobiłem to, aby usunąć elementy z wektora pasującego do określonego wzorca (z regex). – noko

Odpowiedz

16

Definiowanie funktor zamiast:

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")); 

lub C++ 11 stosowania 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; 
    }); 

Należy zauważyć, że moc wektor, second, musi mają elementy przed wywołaniem 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); 

jako predykaty funktor są kopiowane więcej wysiłku jest wymagane aby zachować informacje copied_items. Zobacz Propozycje rozwiązań: Pass std algos predicates by reference in C++.

+0

Wydaje mi się, że podczas próby skorzystania z tego rozwiązania pojawia się błąd dotyczący "nieokreślonego odniesienia", wszelkie pomysły na temat tego, co może się wydarzyć? – noko

+0

@oko, możesz wysłać swój kod do ideału lub podobnego? Zauważ, że kompilator musi obsługiwać lambdy w C++ 11 (w g ++ należy użyć przełącznika kompilatora '-std = C++ 0x'). – hmjd

+0

nieważne, zapomniałem dodać ClassName :: before the function :( – noko

8

Producent funktor, albo używają 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")); 

Przykład z wiążą

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"));