tags:

views:

1331

answers:

4

This may seem to be an academic question, but still I would be very interested in the 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 doing the same using find_if and the compare method of the STL strings as predicate, but how? Something like

find_if(s.begin(), s.end(), bind2nd(mem_fun_ref(&string::compare), string("findme")) );

does not work, because the compare method has several overloads and the compiler does not know which one to choose.

As a second step: My motivation for using find_if instead of find is that I have a vector of objects derived from a class having a string property name and I want to find an object with a given name. Is this possible (without writing an extra function to be used as predicate)?


EDIT: As some (most :) answers mentioned using Boost -- I would prefer not to have to include Boost for this. (As far as I know, most of the Boost libraries are "only" templates, so there should be a way without using Boost.)

A: 

I think you will find that the syntax rapidly gets unweildy, if you are trying to call several functions together. Did you try something like this?

find_if(s.begin(), s.end(), bind2nd(mem_fun_ref(&string::compare), "findme"));

Does this not match the char * overload?

1800 INFORMATION
MSalters
Yes, I tried this, and no, it does not match.
fuenfundachtzig
A: 

If a function has overloaded functions, you can cast the function to correct signature like (void (*)(int,int))(&f).

For your second question, if you use 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);
leiz
Éric Malenfant
I thought that was only in boost::lambda. I agree it is more readable in this case, but i was just trying to demonstrate how to use boost::bind
leiz
The original version of boost::bind did not have those operator overloads, but "recent" (from 1.33) versions have: http://www.boost.org/doc/libs/1_40_0/libs/bind/bind.html#operators
Éric Malenfant
+1  A: 

Select 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 get stuck with the reference to reference problem "Item #50 of Effective STL". And the boost.Bind lib or boost.Lambda is the solution for that.

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")));
TimW
+3  A: 

One option is to cast the member function pointer to suitable type. Another thing you are forgetting is that std::string::compare returns 0 for equal strings, so you'll also need to negate the functor. All in all:

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 to your rationale against boost: its templates are an order of a magnitude more flexible than what you can find in STL functional header. It's either boost, you wait for C++0x lambdas (which I believe will be the preferable way in such situations) or you write some helpers yourself. Currently it can't get 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 it seems the convenience of overloaded operator== will not be there.

UncleBens
This doesn't compile! reference to reference problem.
TimW
Right, not with VC++ (OK for MinGW and Comeau online). I changed to use a different overload which shouldn't exhibit the same problem. (I guess the question is really about what to do in precence of overloads and not specifically how to find a string with find_if and string::compare - which is just stupid, as should be clear.)
UncleBens
One more thing, the presence of overloads is just as much of a problem for boost::bind etc, unless there happens to be another way (such as in this case, using operator== instead of compare).
UncleBens