Что-то, что я должен сделать довольно часто, — это найти члена в коллекции элементов, в которой есть элемент с заданным значением. Например, учитывая:
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 не является унарной функцией)
Есть ли простой способ получить унарную функцию для члена?
Вы можете использовать станд :: 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';
}
}
То, что вы ищете, это std::mem_fn
. Он оборачивает указатель на функцию-член так, что его можно вызвать как свободную функцию, где объект, для которого вызывается функция-член, передается в качестве первого аргумента. В вашем примере вы можете использовать его так:
string toFind = "Alice";
auto iterator = find(people | transformed(std::mem_fn(&Person::getName)) , toFind );
// ^^^^^^^^^^^