我正在尝试为耦合的常微分方程编写一个求解器,这将需要我将多个函数传递给求解器函数。想法是,用户可以在主文件中编写其耦合的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;
}
答案 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::function
,std::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::vector
个std::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
}