Алгоритм поиска элемента в контейнере с заданным значением для одного из его членов

Что-то, что я должен сделать довольно часто, — это найти члена в коллекции элементов, в которой есть элемент с заданным значением. Например, учитывая:

class Person
{
string getName() const {return mName;}
private:
string mName;
};

std::vector<Person> people;

Я хочу найти человека, которого зовут «Алиса». Один из способов сделать это (используя адаптеры диапазона повышения):

string toFind = "Alice";
auto iterator = find(people | transformed([](Person const & p){p.getName()}) , toFind );

это очень много для такой простой операции. Не должно ли быть возможно сделать что-то вроде:

string toFind = "Alice";
auto iterator = find(people | transformed(&Person::getName) , toFind );

(не компилируется, потому что &Person :: getName не является унарной функцией)

Есть ли простой способ получить унарную функцию для члена?

1

Решение

Вы можете использовать станд :: find_if функционировать с соответствующими лямбда который проверяет, если getName() значение равно tofind строка:

std::string tofind = "Alice";
auto it = std::find_if(people.begin(), people.end(), [&tofind](const Person& o) {return o.getName() == tofind; });
if (it != std::end(people)) {
std::cout << "Contains: " << tofind << '\n';
}
else {
std::cout << "Does not contain: " << tofind << '\n';
}

Это потребует getName функция быть в public область видимости, и вы должны предоставить соответствующий конструктор. Полный код будет:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

class Person {
public:
Person(const std::string& name) : mName{ name } {}
std::string getName() const { return mName; }
private:
std::string mName;
};

int main() {
std::vector<Person> people{ {"John"}, {"Alice"}, {"Jane"} };
std::string tofind = "Alice";
auto it = std::find_if(people.begin(), people.end(), [&tofind](const Person& o) {return o.getName() == tofind; });
if (it != std::end(people)) {
std::cout << "Contains: " << tofind << '\n';
}
else {
std::cout << "Does not contain: " << tofind << '\n';
}
}
3

Другие решения

То, что вы ищете, это std::mem_fn. Он оборачивает указатель на функцию-член так, что его можно вызвать как свободную функцию, где объект, для которого вызывается функция-член, передается в качестве первого аргумента. В вашем примере вы можете использовать его так:

string toFind = "Alice";
auto iterator = find(people | transformed(std::mem_fn(&Person::getName)) , toFind );
// ^^^^^^^^^^^
1

По вопросам рекламы [email protected]