如何从C 中的另一个模板函数重新铸造模板函数

How to re-cast a templated function from another templated function in C++

本文关键字:函数 新铸造 另一个      更新时间:2023-10-16

我正在为普通微分方程(ODE(编写一个求解器,并且正在尝试实现运行的时间行为,该行为允许用户从多个ode solvers(例如forward euler方法(中进行选择,第二个和第四阶runge-kutta方法。我正在努力使用一组模板功能,以便用户可以将变量作为映射传递给求解器,其中键可以是intcharstd::string。另外,关联的值可以是floatdouble。在标题为ode_solver()的会员功能中,我需要设置变量class_func等于求解器函数之一,即 euler_methodrk2_methodrk4_method;但是,由于这些功能没有模板,因此我会收到Variable 'class_func' with type auto has incompatible initializer of type <overloaded>的消息。我敢肯定,这是由于C 不允许我动态分配一种类型。代码如下提供。有没有办法启用我在此问题中尝试的行为,还是我不得不放弃模板并仅将数据类型进行编码?.HPP文件中的所有大写字母中突出显示了代码出现问题的区域。我正在使用C 17编译器。

// main.cpp
#include "test.hpp"
#include <iostream>
#include <math.h>
#include <map>
#include <tuple>
double func6(std::map<char, double> arr);
int main(int argc, const char * argv[]) {
    ODESolver q;
    // Code inputs
    std::map<char, double> inputs;
    inputs['x'] = 2.0;
    inputs['y'] = g.e;
    double unc = 0.001;
    double tol = 0.0;
    double step_size = 0.1;
    double start = 2.0;
    double stop = 3.0;
    std::string func_name("Euler");
    std::tuple<std::vector<double>, std::vector<double>> res;
    res = q.new_ode_solver(step_size, start, stop, tol, func_name,
                           inputs, func6);
}
double func6(std::map<char, double> arr)
{
    return arr['y'] * MathKernels::logr(arr['y']) / arr['x'];
}

标题文件是

class ODESolver
{
public:
    template<class char_type, class real_type, class F>
    static inline std::tuple<std::vector<real_type>, std::vector<real_type>>
    ode_solver(real_type step_size, real_type start, real_type stop,
                   real_type error, std::string func_name,
                   std::map<char_type, real_type> &inputs,
                   const F& func)
    {
        // Verify that a correct function name was passed
        if (func_name != "Euler" and func_name != "RK2" and func_name != "RK4")
        {
            std::cout << "FATAL ERROR: ODE Solver Name must be 'Euler', 'RK2' or 'RK4'" << std::endl;
            exit (EXIT_FAILURE);
        }
        // Determine which ODE Solver to use
        // - THIS IS THE PROBLEM, THE COMPILER CANNOT DEDUCE
        //   THE TYPE FROM THE STATEMENT BELOW.
        auto class_func = &ODESolver::euler_method;
        std::tuple<real_type, real_type> res;
        std::vector<char_type> keys;
        std::vector<real_type> x_var;
        std::vector<real_type> y_var;
        keys = get_keys(inputs);
        std::cout << keys[0] << std::endl;
        // Solve ODE
        x_var.push_back(inputs[keys[0]]);
        y_var.push_back(inputs[keys[1]]);
        real_type time = start;
        while (time < stop)
        {
            res = class_func(func, step_size, inputs, keys, error);
            y_var.push_back(std::get<0>(res));
            step_size = std::get<1>(res);
            x_var.push_back(time);
            time += step_size;
            inputs[keys[0]] += step_size;
            inputs[keys[1]] = std::get<0>(res);
        }
        std::tuple<std::vector<real_type>, std::vector<real_type>> value(x_var, y_var);
        return value;
    }
// ================================================================
    template<class char_type, class real_type, class F>
    static inline std::tuple<real_type, real_type>
    euler_method(real_type step_size, std::map<char_type, real_type> inputs,
                 real_type keys, real_type error,
                 const F& func)
    {
        real_type dydx = func(inputs);
        real_type value = inputs[keys[1]] + step_size * dydx;
        std::tuple<real_type, real_type> vals(value, step_size);
        return vals;
    }
// ================================================================
// ================================================================
private:
    template<class char_type, class real_type>
    static inline std::vector<char_type> get_keys(std::map<char_type, real_type> &arr)
    {
        std::vector<char_type> keys;
        for (typename std::map<char_type, real_type>::iterator it = arr.begin();
             it != arr.end(); it++)
        {
            keys.push_back(it -> first);
        }
        return keys;
    }
};

正如其他提到的您正在尝试存储函数的地址,但分配无法分配函数模板的地址!
只需指定模板参数,并且由于ode_solver功能模板中已经存在这些参数(除非不需要这样做(,您可以直接在euler_method函数模板中使用它们。快速修复看起来像:

auto class_func = &ODESolver::euler_method<char_type, real_type, F>;

也在同一类中:

auto class_func = &euler_method<char_type, real_type, F>;

祝你好运!