Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::find Object by Member

Tags:

c++

find

stl

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.

like image 376
Synetech Avatar asked May 08 '13 16:05

Synetech


People also ask

What does find() return C++?

Return value The find() function returns an iterator that points to the val in the specified range. If the value is not found, then it returns an iterator to the last of the array or vector.

How do I find an element in a list STL?

You use std::find from <algorithm> , which works equally well for std::list and std::vector . std::vector does not have its own search/find function. Note that this works for built-in types like int as well as standard library types like std::string by default because they have operator== provided for them.

How do you find the vector of an object?

Finding an element in vector using STL Algorithm std::find() Basically we need to iterate over all the elements of vector and check if given elements exists or not. This can be done in a single line using std::find i.e. std::vector<int>::iterator it = std::find(vecOfNums.


1 Answers

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));
like image 71
Andy Prowl Avatar answered Sep 28 '22 06:09

Andy Prowl