How to use std::find/std::find_if with a vector of custom class objects?
I have a class representing a user ca开发者_高级运维lled Nick
and I want to use std::find_if
on it, where I want to find if the userlist vector has an object included with the same username I pass in. I did a few attempts by trying to create a new Nick
object for the username I want to test and overloading the == operator
and then trying to use find/find_if
on the object:
std::vector<Nick> userlist;
std::string username = "Nicholas";
if (std::find(userlist.begin(), userlist.end(), new Nick(username, false)) != userlist.end())) {
std::cout << "found";
}
I have overloaded the == operator
so comparing Nick == Nick2 should work, but the function returns error C2678: binary '==' : no operator found which takes a left-hand operand of type 'Nick' (or there is no acceptable conversion)
.
Here is my Nick class for reference:
class Nick {
private:
Nick() {
username = interest = email = "";
is_op = false;
};
public:
std::string username;
std::string interest;
std::string email;
bool is_op;
Nick(std::string d_username, std::string d_interest, std::string d_email, bool d_is_op) {
Nick();
username = d_username;
interest = d_interest;
email = d_email;
is_op = d_is_op;
};
Nick(std::string d_username, bool d_is_op) {
Nick();
username = d_username;
is_op = d_is_op;
};
friend bool operator== (Nick &n1, Nick &n2) {
return (n1.username == n2.username);
};
friend bool operator!= (Nick &n1, Nick &n2) {
return !(n1 == n2);
};
};
If you are using C++0X you can use a simple lambda expression
std::string username = "Nicholas";
std::find_if(userlist.begin(), userlist.end(), [username](Nick const& n){
return n.username == username;
})
You have to define operator== with two Objects outside your class, as a tool function, not a member.
Then to make it friend just put the declaration of the function inside the class.
try something like this:
class Nick {
public:
friend bool operator== ( const Nick &n1, const Nick &n2);
};
bool operator== ( const Nick &n1, const Nick &n2)
{
return n1.username == n2.username;
}
Also your find should look like this:
std::find(userlist.begin(), userlist.end(), Nick(username, false) );
No need of "new".
I know that you wanted to overload the ==
operator, but the same thing can easily be done with a predicate:
struct UsernameIs {
UsernameIs( string s ) : toFind(s) { }
bool operator() (const Nick &n)
{ return n.username == toFind; }
string toFind;
};
int main()
{
vector<Nick> vn(10);
string nameToFind = "something";
find_if(vn.begin(), vn.end(), UsernameIs(nameToFind));
}
Note that in C++0x, you can do the same thing with a lambda expression much more concisely.
You are passing a pointer to the find function. Drop the new:
std::find(userlist.begin(), userlist.end(), Nick(username, false))
Also, your operators should accept their arguments by const reference, they don't modify them.
bool operator== (const Nick &n1, const Nick &n2)
I am noticing you are trying to call one constructor from another in this manner:
Nick(std::string d_username, bool d_is_op) {
Nick();
...
Well, sorry, but this doesn't work. The line Nick()
just creates a temporary and doesn't affect this
. Constructor forwarding is only possible in C++0x (the upcoming standard)
As to your problem - this question asked a couple of days ago about binary_search covers the same grounds. The top answer is just awesome.
Mystical restriction on std::binary_search
HTH.
P.S. Ideally this should have been a comment, but it's just too verbose
You can use boost::bind
std::find_if( userlist.begin(), userlist.end(),
boost::bind( & Nick::isFound,
_1 ) );
just implement bool Nick::isFound()
You can also pass the criteria
std::find_if( userlist.begin(), userlist.end(),
boost::bind( & Nick::compare,
_1,
nick ) );
implement
bool Nick::compare( const Nick & nick )
{
return this->username == nick.username;
}
This works for me:
Nick.h
#include <string>
class Nick {
private:
Nick() {
username = interest = email = "";
is_op = false;
};
public:
std::string username;
std::string interest;
std::string email;
bool is_op;
Nick(std::string d_username, std::string d_interest, std::string d_email, bool d_is_op) {
Nick();
username = d_username;
interest = d_interest;
email = d_email;
is_op = d_is_op;
};
Nick(std::string d_username, bool d_is_op) {
Nick();
username = d_username;
is_op = d_is_op;
};
bool operator==(const Nick& refNick) const
{
if (username != refNick.username)
return false;
if (interest != refNick.interest)
return false;
if (email != refNick.email)
return false;
if (is_op != refNick.is_op)
return false;
return true;
}
bool operator!=(const Nick& refNick) const
{
if (username == refNick.username)
return true;
if (interest == refNick.interest)
return true;
if (email == refNick.email)
return true;
if (is_op == refNick.is_op)
return true;
return false;
}
};
main.cpp
#include <iostream>
#include <string>
#include <vector>
#include "Nick.h"
int main()
{
std::vector<Nick> userlist;
std::string username = "Nicholas";
Nick Nicholas(username, false);
Nick John("John", true);
userlist.push_back(Nicholas);
std::vector<Nick>::iterator it;
it = std::find(userlist.begin(), userlist.end(), Nick("Nicholas", false));
if(it != userlist.end())
std::cout << "\n" << Nicholas.username << " was found.";
else
std::cout << "\n" << Nicholas.username << " was not found.";
it = std::find(userlist.begin(), userlist.end(), John);
if (it != userlist.end())
std::cout << "\n" << John.username << " was found.";
else
std::cout << "\n" << John.username << " was not found.";
}
Result
Nicholas was found.
John was not found.
精彩评论