Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
594 views
in Technique[技术] by (71.8m points)

c++ - std::find Object by Member

Scenario

I’ve run into a speedbump while using the STL with what seems like a normal scenario, simplified here:

class Person {
  string Name;
  int    Age;
};

vector<Person> people;
AddPeople(people);

string s("Bob");
find(people.begin(), people.end(), s);

Problem

Unfortunately find wants to compare the entire class.

Question

Is there a better or more appropriate way to do this the “STL way”? The suggested questions weren’t helpful, but I managed to find a couple of related questions but no direct solution.

Work-arounds/Tests

There’s some potential work-arounds:

  1. Forgo find altogether (cluttered, but could be refactored):

    bool bBob = false; for (UINT i = 0; i < people.size(); i++) { if (people[i].Name == s) bBob = true; break; }

  2. Provide conversion operator (implicit conversion doesn’t work; explicit can’t be used in find):

    class Person { string Name; int Age; operator string() {return Name;} };

    Person b ("Bob", 99); string s ("Bob"); b == s; //doesn’t work string(b) == s; //works, but no good for find()

  3. Define a standalone equality operator (simple, effective, but globally exposed):

    BOOL operator==(Person l, string r) { return l.Name == r; }

  4. Define a member equality operator (makes comparison order dependent; object must be first):

    class Person { string Name; int Age; bool operator==(string s) {return Name == s;} };

    Person b ("Bob", 99); string s ("Bob"); b==s; //works s==b; //doesn’t work, but not a problem for find()

It looks like #4 is the best candidate, but none seem ideal or feel “STL”, and some have problems.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Is there a better or more appropriate way to do this the “STL way”?

You can use std::find_if (powered by C++11 lambdas):

std::string name = "Bob";
// ...
std::find_if(std::begin(people), std::end(people), 
    [&] (Person const& p) { return p.Name == name; }

Notice, that calling it "STL way" is inappropriate. This is the C++ Standard Library, not the STL ("Standard Template Library"). The STL served as a strong inspiration for the Containers and Algorithms Library of the C++ Standard Library, but the two things are not the same. See this Q&A on StackOverflow for further information.

EDIT:

Since you are using a compiler that does not support lambdas, you can define your own functor predicate:

struct person_has_name
{
    person_has_name(std::string const& n) : name(n) { }  
    bool operator () (Person const& p) { return p.Name == name; }
private:
    std::string name;
};

And use it with std::find_if this way:

std::string name = "Bob";
// ...
std::find_if(people.begin(), people.end(), person_has_name(name));

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...