Как создать std :: vector функций без явного определения функций? - PullRequest
4 голосов
/ 27 декабря 2011

Я хочу создать объект std :: vector (или любой другой стандартный или нестандартный тип контейнера) с элементами пользовательских и произвольных функций, сигнатуры которых одинаковы.

Это должно быть примерно так:

// Define the functions and push them into a vector
std::vector<????> MyFunctions;
MyFunctions.push_back(double(int n, float f){ return (double) f / (double) n; });
MyFunctions.push_back(double(int n, float f){ return (double) sqrt((double) f) / (double) n; });
// ...
MyFunctions.push_back(double(int n, float f){ return (double) (f * f) / (double) (n + 1); });

// Create an argument list
std::vector<std::pair<int, float>> ArgumentList;
// ...

// Evaluate the functions with the given arguments
// Suppose that it is guarantied that ArgumentList and MyFunctions are in the same size
std::vector<double> Results;
for (size_t i=0; i<MyFunctions.size(); i++)
{
    Results.push_back(MyFunctions.at(i)(ArgumentList.at(i).first, ArgumentList.at(i).second));
}

Если возможно, я не хочу явно определять этот набор функций, как показано ниже:

class MyClass
{
    public:
        void LoadFunctions()
        {
            std::vector<????> MyFunctions;
            MyFunctions.push_back(MyFoo_00);
            MyFunctions.push_back(MyFoo_01);
            MyFunctions.push_back(MyFoo_02);
            // ...
            MyFunctions.push_back(MyFoo_nn);
        }

    private:
        double MyFoo_00(int n, float f) { /* ... */ }
        double MyFoo_01(int n, float f) { /* ... */ }
        double MyFoo_02(int n, float f) { /* ... */ }
        // ...
        double MyFoo_nn(int n, float f) { /* ... */ }
};

Реализация с некоторым стандартным библиотечным инструментом (например, с использованием std::function) в порядке. Но нестандартный способ сделать это (например, использовать Boost , QT или любую другую библиотеку или инфраструктуру) не является предпочтительным.

Ответы [ 4 ]

6 голосов
/ 27 декабря 2011

Звучит так, как вы хотите лямбда-функции . Если ваш компилятор C ++ реализует эту часть стандарта C ++ 11, вы можете использовать их напрямую. В противном случае вы можете использовать Boost Phoenix или Boost Lambda .

3 голосов
/ 27 декабря 2011

Если ваш компилятор достаточно современен, вы можете использовать новые функции типа std::function и анонимные (лямбда) функции, представленные в C ++ 11:

std::vector<std::function<double(int, float)>> MyFunctions;
MyFunctions.push_back([](int n, float f) {
    return (double) f / (double) n;
});
MyFunctions.push_back([](int n, float f) {
    return (double) sqrt((double) f) / (double) n;
});
// ...
MyFunctions.push_back([](int n, float f) {
    return (double) (f * f) / (double) (n + 1);
});
2 голосов
/ 27 декабря 2011

Вы можете сделать это, используя std::function и лямбды:

#include <vector>
#include <functional>
#include <iostream>
#include <algorithm>
#include <iterator>

struct dispatcher {
  template <typename F, typename Pair>
  double operator()(const F& func, const Pair& p) const {
    return func(p.first, p.second);
  }
};

int main() {
  std::vector<std::function<double(int,double)>> functions;
  functions.push_back([](int n, float f) { return double(f)/double(n); });

  std::vector<std::pair<int, float>> args = {std::make_pair(1, 10.0f)};

  std::vector<double> results;

  std::transform(functions.begin(), functions.end(), args.begin(), std::back_inserter(results), dispatcher());

  std::copy(results.begin(), results.end(), std::ostream_iterator<double>(std::cout, "\n"));
}
0 голосов
/ 20 марта 2019

Указателей на функции вполне достаточно, нет необходимости использовать даже std :: function:

#include<iostream>
#include<vector>
#include<cmath>

int main()
{
      std::vector<double (*)(double)> vec;
      vec.push_back([](double x) {return cos(x);});
      vec.push_back([](double x) {return sin(x);});
      vec.push_back([](double x) {return tan(x);});
      for (auto f: vec)
          std::cout<<f(M_PI/4)<<'\n';
      return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...