c++ - 将一个函数传递给 C++ 中的另一个函数,其中参数的数量可以不同

标签 c++ c++17 decorator

我正在处理 C++17 中的一个问题,我正在构建一个根求解器,允许用户将用户定义的函数传递给根求解函数。下面显示了 .cpp 文件的类示例,原型(prototype)位于 .hpp 文件中。

// root.cpp
double RootSolver::newton(double guess, double right_side,
                          double (*func)(double),
                          double unc, int iter)
/**
Finds a specific root of a function using the Newton iteration
method

 @param guess      An initial guess for the value of the root
 @param right_side The value of the right side of the
                   function.
 @param func       The function for which the root will be
                   determined
 @param unc        The uncertainty or tolerance in the accepted
                   solution.  Defaulted to 0.001
 @param iter       The number of iterations to try before the
                   function fails.  Defaulted to 150.
 @return root
 */
{
    double x1, x2, x3, y1, y2, slope;
    x1 = guess;
    x2 = x1 + 0.0000001;
    for (int i = 0; i < iter; i++)
    {
        y1 = func(x1) - right_side;
        y2 = func(x2) - right_side;
        slope = (y2 - y1) / (x2 - x1);
        x3 = x1 - (y1 / slope);
        if (func(x3) - right_side <= unc and
            func(x3) - right_side >= -unc) return x3;
        x1 = x3;
        x2 = x1 + 0.0000001;
    }
    exit_program(iter);
}
// ================================================================
// RootSolver PRIVATE FUNCTIONS

[[noreturn]] void RootSolver::exit_program(int iter)
{
    std::string one("Function did not converge within ");
    std::string two(" iterations");
    std::cout << one << iter << two << std::endl;
    exit (EXIT_FAILURE);
}

主文件是这样的;

double func1(double x);
double func2(double x, double a, double b);
int main() {
    RootSolver q;
    double guess = 2.0;
    double right_side = 0.0;
    // This function works fine
    result = q.newton(guess, right_side, func1)

    // - Not sure how to reformat RootSolver.newton so
         I can pass it func1 as well as func2 so it can
         accept the arguments a and b
    return 0;
}

double func1(double x)
{
    return pow(x, 6) - x - 1.0;
}

double func2(double x)
{
    return pow(x, 6) - a * x - b * 1.0;
}

上面显示的代码非常适用于 func1,因为 x 是唯一的参数;但是,我不确定如何重新格式化 RootSolver.newton 函数,以便它接受 func1 除了 x 之外没有参数并接受 func2 和参数 ab。有谁知道我如何将参数传递给函数 newton,这样它就不会针对特定的输入函数进行硬编码?

最佳答案

根据粗略的描述,调用方 lambda 听起来像是解决了您的问题:

result = q.newton(guess, right_side, [](double x) {
    return func2(x, 0, 0); // Replace 0s with values of a and b.
});

此 lambda 根据需要转换为 double(*)(double)。请注意,如果您需要捕获某些内容,这将不起作用,因为函数指针无法存储额外的状态。有两种简单的方法可以解决这个问题。

  1. 制作模板(并将定义放在标题中):

    template<typename F>
      // requires std::is_invocable_r_v<double, F, double> // C++20 constraint option A
      // requires requires(F f, double x) { f(x) -> double; } // C++20 constraint option B - can be extracted into a concept
    double RootSolver::newton(double guess, double right_side,
                              F func,
                              double unc, int iter)
    
  2. 使用 std::function,但调用它时会牺牲一些性能:

    double RootSolver::newton(double guess, double right_side,
                              const std::function<double(double)>& func,
                              double unc, int iter)
    

关于c++ - 将一个函数传递给 C++ 中的另一个函数,其中参数的数量可以不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56015467/

相关文章:

c++ - 错误:<位/stdc++。h>,未找到 'cstdalign'文件,正在运行C++ 17

c++ - 当数组对象的元素存储被重用时,它的生命周期是否结束?

Python,有条件地使用装饰器(未在所有环境中安装包)

javascript - vscode 是否支持 decorator after export default?如何启用此功能?

c++ - cvWaitKey() 显着减慢捕获过程 - 解决方法?

c++ - 根据参数调用不同函数的宏

c++ - 如何分配给结构对象的成员?

python 装饰器 *args 和 ** kwargs

c++ - 如何创建特定(R,G,B)颜色的openCV图像并获取该颜色名称?

c++ - 枚举电池设备 c++ windows