Using find_if on std :: vector <std :: string> with bind2nd and string :: compare
This may seem like an academic question, but still I'd be very interested in an answer:
I have a vector of strings s
in which I would like to find a given string findme
. This can be done using something like
find(s.begin(), s.end(), findme);
My question is, there must be a way to do the same using a method find_if
and compare
STL strings as a predicate, but how? Something like
find_if(s.begin(), s.end(), bind2nd(mem_fun_ref(&string::compare), string("findme")) );
doesn't work because the comparison method has multiple overloads and the compiler doesn't know which one to choose.
As a second step: The motivation for using find_if instead of find is that I have a vector of objects obtained from a class that has a string property name
and I want to find an object with a given name. Is this possible (without writing an additional function to be used as a predicate)?
EDIT: like some (most :) answers mentioned with Boost - I'd rather not include Boost for this. (As far as I know, most Boost libraries are "only" templates, so there must be a way without using Boost.)
source to share
One option is to provide a member function pointer for the appropriate type. Another thing you are forgetting is that std :: string :: compare returns 0 for equal strings, so you will need to negate the functor as well. Total:
std::find_if(
vec.begin(), vec.end(),
std::not1(
std::bind2nd(
std::mem_fun_ref(static_cast<int (std::string::*)(const char*)const>(&std::string::compare)),
"findme"
)
)
);
As for your rationale against escalation: its templates are orders of magnitude more flexible than what you can find in the STL functional header. This either reinforces, you are waiting for C ++ 0x lambdas (which I believe would be the preferred way in situations like this), or you write some helpers yourself. Currently, it cannot be simpler than:
std::find_if(vec.begin(), vec.end(), boost::bind(&X::name, _1) == "findme");
FYI, C ++ 0x will add std :: bind, which is similar to boost :: bind, but there seems to be no convenience of the overloaded == operator.
source to share
Choose the correct overload yourself.
int (string::*compare)(const string&) const;
compare = &string::compare;
find_if(s.begin(), s.end(), bind2nd( mem_fun_ref(compare), string("findme")));
But then you are stuck with a reference to the "Item # 50 of Effective STL" reference issue. And boost.Bind lib or boost.Lambda is the solution for this.
int (string::*compare)(const string&) const;
compare = &string::compare;
find_if(s.begin(), s.end(), bind(compare, _1, "findme")==0);
Or
find_if(s.begin(), s.end(), bind2nd(std::equal_to<string>(), string("findme")));
source to share
If the function has overloaded functions, you can use the function to properly sign, eg
(void (*)(int,int))(&f)
.
For your second question, if you are using boost you can do something like this,
find_if(s.begin(), s.end(), boost::bind(std::equal_to<string>(), boost::bind(&SomeClass::name, _1), name);
source to share