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
Most predicates take one, two, or three arguments. A predicate and its arguments form a predicate-argument structure.
You are asking for default value, right? Otherwise, define NoFilter as Predicate<things> and pass it . You can have a default value of null and you'd have to check for that in your code. Alternatively you could overload the method with a second one that doesn't take a predicate.
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.
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"));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With