简体   繁体   中英

Using find_if on std::vector<std::string> with bind2nd and string::compare

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

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.

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

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

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?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM