Как правильно спроектировать функтор, который будет извлекать различные поля из структуры
У меня есть std::vector
из struct
s, которые содержат несколько полей, например:
struct stats
{
double mean;
double median;
double rms;
};
std::vector<stats> data;
Я хотел бы разработать функцию, которая работает на vector
Например, строит гистограмму. Я хотел бы иметь возможность указать, что подано из struct
Если эта функция работает. Например:
build_histogram(data, get_mean);
build_histogram(data, get_median);
build_histogram(data, get_rms);
Я пытался реализовать некоторые геттеры в stats
класс, как это:
struct stats
{
double mean;
double median;
double rms;
struct get_mean { double operator() () { return mean; };
struct get_median { double operator() () { return median; };
struct get_rms { double operator() () { return rms; };
};
Но это говорит о том, что это недопустимое использование нестатических членов mean
, median
а также rms
, Как я могу правильно это реализовать?
2 ответа
Вы пытаетесь передать тип, а не объект. При выполнении итерации контейнера функтор должен принимать элемент вектора в качестве параметра. Есть несколько способов сделать это, наиболее похожий на то, что вы пытаетесь сделать:
struct stats
{
double mean;
double median;
double rms;
struct get_mean { double operator() (const stats& s) { return s.mean; } };
struct get_median { double operator() (const stats& s) { return s.median; } };
struct get_rms { double operator() (const stats& s) { return s.rms; } };
};
build_histogram(data, stats::get_mean());
build_histogram(data, stats::get_median());
build_histogram(data, stats::get_rms());
Однако, если у вас есть поддержка лямбд (новая в C++11), их проще использовать.
struct stats
{
double mean;
double median;
double rms;
};
build_histogram(data, [](const stats& s) { return s.mean; });
// etc.
Чтобы любой из них работал build_histogram
должен быть шаблоном функции со вторым параметром, являющимся любым вызываемым объектом (изменение ReturnType
при необходимости).
template <typename F>
ReturnType build_histogram(const std::vector<stats>& data, F functor)
{
// here you can use functor() or pass it to STL algorithm (e.g. find_if)
}
Различные способы определения функторов (более или менее в порядке моих предпочтений)
- лямбда-функция (C++11)
- свободная функция
- объект functor (это то, что вы сделали, но он не должен быть вложенным в тип)
- статическая функция-член
- функции-члены, использующие
std::bind
(Я бы не советовал это)
Зачем изобретать кортеж?
enum {mean, median, rms};
typedef std::tuple<double,double,double> stats;
stats st{1,2,3};
cout << get<mean>(st);