I have a vector of Models
like below:
struct Model
{
std::string mName;
// .......
};
Given a string representing a model name, I want to see if I can find one of the models in the vector.
Right now I have this:
std::string assetName = "monkey";
std::vector<Model>::iterator iter = std::find_if(mModels.begin(), mModels.end(), boost::bind(&Model::mName, _1) == assetName);
But this does not do case insensitive string comparison. So I read about boost/algorithm/string.hpp
, with boost::iequals
, that does this correctly.
Here's my attempt at using it:
std::vector<Model>::iterator iter = std::find_if(mModels.begin(), mModels.end(), boost::iequals(boost::bind(&Model::mName, _1), assetName));
Yet this does not compile and reports some hundred lines of compilation errors. I believe std::find_if expects a third param function with only 1 parameter.
is there a simple fix for this?
EDIT: I forgot to mention I cannot use C++11, but I can use boost!
EDIT2: The answer below seems to give me this compilation error, using this:
std::vector<Model>::iterator iter = std::find_if(mModels.begin(), mModels.end(), boost::bind(&boost::iequals<std::string, std::string>, boost::bind(&Model::mName, _1), assetName));
bind.hpp(69): error C2825: 'F': must be a class or namespace when followed by '::'
2> bind\bind_template.hpp(15) : see reference to class template instantiation 'boost::_bi::result_traits<R,F>' being compiled
2> with
2> [
2> R=boost::_bi::unspecified,
2> F=bool (__cdecl *)(const std::string &,const std::string &,const std::locale &)
2> ]
2> resourcemanifest.cpp(24) : see reference to class template instantiation 'boost::_bi::bind_t<R,F,L>' being compiled
2> with
2> [
2> R=boost::_bi::unspecified,
2> F=bool (__cdecl *)(const std::string &,const std::string &,const std::locale &),
2> L=boost::_bi::list2<boost::_bi::bind_t<const std::basic_string<char,std::char_traits<char>,std::allocator<char>> &,boost::_mfi::dm<std::string,Model>,boost::_bi::list1<boost::arg<1>>>,boost::_bi::value<std::string>>
2> ]
boost::iequals(boost::bind(&Model::mName, _1), assetName)
The bind is a red herring: this is currently not a functor, but a function call.
You're (accidentally) trying to call it immediately, and use the boolean result as the comparison function for std::find_if
. Naturally, that's not correct.
You were right to bind the model name, but you'll still have to bind the actual call to iequals
, too.
Here's a prior example on the Boost users' mailing list - first Google result for bind iequals
.
Try something like:
boost::bind(
&boost::iequals<std::string,std::string>,
boost::bind(&Model::mName, _1), // 1st arg to iequals
assetName, // 2nd arg to iequals
std::locale() // 3rd arg to iequals
)
Notice that template argument deduction is not possible here; also notice that we have to provide boost::iequals
's default third argument explicitly, because defaults don't provide us the magic of being able to omit arguments when binding functions.
Full working testcase:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <boost/bind.hpp>
#include <boost/algorithm/string/predicate.hpp>
struct Model
{
Model(const std::string& name) : name(name) {};
std::string mName() const
{
return name;
}
private:
std::string name;
};
int main()
{
std::vector<Model> mModels;
mModels.push_back(Model("a"));
mModels.push_back(Model("b"));
mModels.push_back(Model("c"));
const std::string assetName = "B";
std::vector<Model>::iterator it = std::find_if(
mModels.begin(),
mModels.end(),
boost::bind(
&boost::iequals<std::string,std::string>,
boost::bind(&Model::mName, _1),
assetName,
std::locale()
)
);
assert(it != mModels.end());
std::cout << it->mName() << std::endl; // expected: "b"
}
(See it working live here.)
In boost::bind(&Model::mName, _1) == assetName
, the operator ==
is overloaded when used with boost::bind
to do magic; although it looks like you're doing a direct comparison, the comparison is not actually evaluated in the argument to std::find_if
, but deferred until later (essentially by performing an implicit bind
that you can't see).
In the case of a normal function call, though, such as to boost::iequals
, we have to apply that "magic" ourselves, which is what the above is all about.
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