21

I'm trying to filter a vector so it contains only a specific value.

e.g. Make sure the vector only contains elements of the value "abc."

Right now, I'm trying to achieve this with remove_copy_if.

Is there any way to pass an additional parameter to a predicate when using one of std's algorithms?

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

I'm hoping to pass the following function as a predicate but it seems more likely that this would just end up comparing the current value being examined by remove_copy_if and the next.

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

I have a feeling I'm probably approaching this wrong so any suggestions would be appreciated!

Thanks

2
  • Just wondering - what do you use a vector with only identical elements for? Commented Nov 23, 2012 at 10:15
  • I tried to make my example as simple as possible so it made sense :) What I did with this was to remove elements from a vector that fit a certain pattern (with regex). Commented Nov 23, 2012 at 10:36

2 Answers 2

29

Define a functor instead:

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

or if C++11 use a 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; }); 

Note that the output vector, second, must have elements before the call to 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); 

As functor predicates are copied more effort is required to retain the copied_items information. See Pass std algos predicates by reference in C++ for suggested solutions.

Sign up to request clarification or add additional context in comments.

3 Comments

I seem to get an error about an "undefined reference" when I try to use this solution, any ideas on what might be happening?
@noko, can you post you code to ideone or similar? Note you compiler must support C++11 lambdas (in g++ you need to use -std=c++0x compiler switch).
never mind, I forgot to add a ClassName:: before the function :(
10

Make functor, or use 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")); 

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.