在C ++中将多个函数传递给向量中的另一个函数

时间:2019-05-23 01:14:54

标签: c++ c++17

我正在尝试为耦合的常微分方程编写一个求解器,这将需要我将多个函数传递给求解器函数。想法是,用户可以在主文件中编写其耦合的ODE函数,调用框架头文件,并将其函数传递给框架以解决ODE。

在某些情况下,可能只有两个功能,在其他情况下,可能有三个,四个或更多功能。我试图通过将耦合函数封装在向量中来实现此目的,并且我想在此过程中调用std :: function包装器。下面,我显示了类似代码的简化版本。目前,我正在尝试定义一种将函数封装在数组中的方法,以便可以将其传递给solver函数。我正在使用带有clang的C ++ 17编译器。有没有办法在数组中传递这些函数,或者有我不知道的更好的方法呢?

double func1(std::map<std::string, double> arr)
{
    dydt = arr["one"] * 3.0 - arr["two"];
    return dydt;
}

double func2(std::map<std::string, double> arr)
{
    dydt = 1 / arr["three"] + 3.0 * arr["two"];
    return dydt;
}

double solver(std::vector<std::function<double(std::map<std::string, double>) &funcs, std::map<std::string, double> inputs)
{
    double res;
    std::vector<double> data;
    for (int i = 0; i < funcs.size(); i++)
    {
        // - The ODE solver is not shown in this example, 
        //   but it highlights the general intent
        res = funcs[i](inputs);
        data.push_back(res);
    }
    return data;
}

int main()
{
    std::map<std::string, double> inputs;
    inputs["one"] = 1.0;
    inputs["two"] = 2.0;
    inputs["three"] = 3.0;
    inputs["four"] = 4.0;

    // The line of code below does not work
    std::vector<std::function<double(std::map<std::string, double>)>> funcs = {func1, func2};
    std::vector<double> dat;

    // - Due to the fact that the array of funcs does not work, 
    //  this function call also does not work
    dat = solver(funcs, inputs);
    return 0;
}

2 个答案:

答案 0 :(得分:1)

由于您将问题标记为C ++ 17,因此可以将可变参数函数模板与fold expression一起使用:

template<typename ...Funcs>
std::vector<double> solver(const std::map<std::string, double>& inputs, Funcs&&... funcs)
{
    std::vector<double> results;
    (results.push_back(funcs(inputs)), ...);
    return results;
}

出于性能原因,我将参数类型更改为const std::map<std::string, double>&。建议在此处通过引用(&)传递。按值传递将在每个函数调用上复制std::map。因此,函数应声明为:

double func1(const std::map<std::string, double>& arr);

现在,您不再需要向量即可传递函数。您可以直接将它们作为参数传递给solver

int main()
{
    std::map<std::string, double> inputs {
        {"one", 1.0},
        {"two", 2.0},
        {"three", 3.0},
        {"four", 4.0}
    };

    auto results = solver(inputs, func1, func2);
}

请注意,solver函数模板接受任何可调用的函数。例如Lambda也可以:

solver(inputs,
    [](auto arr){ return arr["one"] * 3.0 - arr["two"]; },
    [](auto arr){ return 1 / arr["three"] + 3.0 * arr["two"]; }
);

(如果您更容易理解,则可以使用const std::map<std::string, double>& arr代替auto arr。请注意,lambda中的auto意味着lambda成为模板。)

答案 1 :(得分:0)

您可以使用std::functionstd::any和参数包的组合来做到这一点:

#include <functional>
#include <string>
#include <map>
#include <any>
#include <vector>

using my_f_type = std::function<int(std::map<std::string, int>&)>;

template<typename...T>
int solver(const T& ... functions) {
    std::vector<std::any> vec = { functions... };
    std::map<std::string, int> foo = { { "test", 37 } };
    for (auto& f : vec) {
        try {
            return std::any_cast<my_f_type>(f)(foo);
        } catch (const std::bad_any_cast& e) {}
    }
    return 0;
}

int main() {
    std::function<int(int)> a = [](int a) { return a; };
    std::function<double(double)> b = [](double b) {return b; };
    my_f_type c = [](std::map<std::string, int>& c) { return c["test"]; };
    return solver(a, b, c);
}

main中,您有要传递给接受n个参数的solver的函数列表。然后,您传递的函数存储在std::vectorstd::any中。在此示例中,try catch仅是一种使用情况,在这里我只想调用c函数。 main的返回值为37。

我想在这里展示不同类型的功能。但是,如果您的函数始终是同一类型,则可以使用std::any丢弃(现在传递foo):

#include <string>
#include <map>

template<typename...T>
int solver(std::map<std::string, int>& foo, const T& ... functions) {
    return (functions(foo) + ...);
}

int main() {
    std::map<std::string, int> foo = { { "a",1 },{ "b",2 },{ "c",3 } };
    auto a = [](std::map<std::string, int>& a) { return a["a"]; };
    auto b = [](std::map<std::string, int>& b) { return b["b"]; };
    auto c = [](std::map<std::string, int>& c) { return c["c"]; };
    solver(foo, a, b, c); // returns 6
}