Можно ли элегантно запустить стандартные алгоритмы на векторе <MyType>? - PullRequest
0 голосов
/ 26 сентября 2011

Я знаю, если у меня есть vector<int>, я могу запускать алгоритмы на нем следующим образом:

int max = *max_element(myints.begin(), myints.end());

Но что если у меня есть vector<MyStruct>, где одно из полей в структуре является целым,Есть ли хороший элегантный способ запустить алгоритм только для целых чисел во всех моих структурах?

Ответы [ 5 ]

11 голосов
/ 26 сентября 2011

Предоставить компаратор для max_element:

MyStruct max = *max_element(v.begin(), v.end(),
    [](const MyStruct & lhs, const MyStruct & rhs) { return lhs.theInt < rhs.theInt; });

Если ваш компилятор еще не поддерживает лямбда-выражения, вам придется написать отдельную функцию или класс объекта функции.

В качестве альтернативы, если вы перегрузите operator< для своего класса, чтобы выполнить такое же сравнение, то вы можете просто сделать это:

MyStruct max = *max_element(v.begin(), v.end());
4 голосов
/ 26 сентября 2011

Это зависит от того, как вы определяете «элегантный», но да, это можно сделать. На самом деле, разными способами.

В Стандартном C ++ вы можете использовать Функтор:

#include <algorithm>
#include <vector>
#include <functional>
using namespace std;

class Gizmo
{
public:
    int n_;
};

class BiggestGizmo : public std::binary_function<bool, Gizmo, Gizmo>
{
public:
    bool operator()(const Gizmo& lhs, const Gizmo& rhs) const
    {
        return lhs.n_ > rhs.n_;
    }
};

int main()
{
    typedef vector<Gizmo> Gizmos;
    Gizmos gizmos;
    Gizmos::const_iterator it = max_element(gizmos.begin(), gizmos.end(), BiggestGizmo());
}

В C ++ 0X вы можете использовать лямбду:

#include <algorithm>
#include <vector>
using namespace std;

class Gizmo
{
public:
    int n_;
};

int main()
{
    typedef vector<Gizmo> Gizmos;
    Gizmos gizmos;
    Gizmos::const_iterator it = max_element(gizmos.begin(), gizmos.end(), [](const Gizmo& lhs, const Gizmo& rhs) -> bool
    {
        return lhs.n_ > rhs.n_;
    });
}
2 голосов
/ 26 сентября 2011

Еще один вариант в миксе: вы можете написать свой собственный класс итераторов, чьи типы ссылок и значений равны int& и int, но который действует поверх итератора со ссылочным типом MyStruct&, предоставляя доступ кэто поле.

Это немного больше, чем просто предоставление дополнительного компаратора для max_element, но если вы сделаете это один раз, то вы сделали это для всех алгоритмов, а не толькоте, которые действуют через компаратор.Если вы можете использовать его, boost::transform_iterator будет обрабатывать шаблон для вас.

boost::transform_iterator не позволяет вернуть базовый итератор из экземпляра, но в случае vector, который не 'Это не имеет большого значения, так как это произвольный доступ, поэтому эффективно вычислить расстояние и применить его к итератору begin().

1 голос
/ 26 сентября 2011

Для структур вы можете определить функцию сравнения или объект.Вы также можете определить оператор < для своей структуры.Вот пример .

0 голосов
/ 26 сентября 2011

Как вы сказали в одном из комментариев, у вас много учеников, и вы хотите обратиться к каждому по отдельности в алгоритмах.Вы получаете различные возможности

  • лямбда-выражений повсюду (либо Phoenix, либо C ++ 11)
  • функторы для каждого случая
  • функций-членов для каждого случая

Я бы предпочел последние два решения, только если бы мне нужно было повторять лямбды в разных местах (или если бы мне пришлось использовать Феникс, но это просто личное дело).

struct Foo {
  int a;
  int b;
  bool less_than_by_a(const Foo&) const;
  bool less_than_by_b(const Foo&) const;
};

std::max_element(begin, end, std::mem_fun_ref(&Foo::less_than_by_a));
std::max_element(begin, end, std::mem_fun_ref(&Foo::less_than_by_b));
...