将数学函数作为方法的输入参数C ++传递

时间:2017-09-09 18:24:58

标签: c++ function templates lambda

我正在尝试编写一个通用的积分函数,我想以这样的方式实现它,以便它可以接受任何数学函数。也就是说,我想将数学函数作为输入参数传递。在伪代码中:simpson_int(x*x)。我听说过function中的<functional>模板,但我对C ++中的模板并不熟悉。

2 个答案:

答案 0 :(得分:3)

我脑子里有一些解决方案(这是我对这个问题的处理方法,肯定有更多的解决方案,也许我指出的不是最好的),考虑到这个问题你需要在Simpson实现中多次调用参数函数(因此你需要一个&#34;可调用&#34;参数):

函数指针

函数指针(比C ++更多),用两个参数声明:第一个是指向具有指定类型的函数的指针,而第二个是函数的参数。让我们 举个例子:

#include <iostream>

double power2(double x) {
  return x * x;
}

double simspon(double (*f)(double), double x) {
  return f(x);
}

int main() {
  std::cout << simspon(power2, 2);
  return 0;
}

在这种情况下,我没有使用模板来达到结果。但是这将将任何函数作为第一个参数,但只有一个函数将参数作为double并返回一个double。

我认为大多数c ++程序员都会建议你避免使用这种方法。

函数指针和模板

因此,您可能希望使用模板扩展前一个示例并使其更加通用。重新定义函数非常简单 接受仅在代码中使用时实际指定的模板(抽象类型):

#include <iostream>

double power2(double x) {
  return x * x;
}

int power2int(int x) {
  return x * x;
}

template <class T, class P>
P simspon(T (*f)(P), P x) {
  return f(x);
}

int main() {
  std::cout << simspon<double, double>(power2, 2.0);
  std::cout << simspon<int, int>(power2int, 2);
  return 0;
}

TP是两个模板:第一个用于描述函数指针的返回值,第二个用于指定函数指针的参数,返回值为{ {1}}。因此,当您编写simpson时,您实际上是在通知编译器您正在使用T和P作为不同类型的占位符。实际上,当您在template <class T, classP>中调用该函数时,您将实际声明您想要的类型。 这不是好代码,但我正在构建理解模板的路径。此外,当您使用main实际调用simpson时,指定参数函数的类型

免责声明>您应该考虑使用< >代替课程。但我已经使用了旧的template <typename T ...>,并且存在class的情况1}}无法使用,SO上有很多问题可以深入研究。)

使用typename

您可能希望创建一个存储要作为std::function参数传递的函数的变量,而不是使用函数指针作为参数。这带来了几个优点,因为它们实际上是代码中的一个对象,在某些不需要的情况下具有一些可预测的行为(例如,在null函数指针的情况下,你必须检查指针本身并处理它,如果是{{ 1}}如果没有可调用指针,则抛出simpson错误)

这是一个示例,它再次使用模板,如前所述:

std::function

使用lambdas

lambdas是闭包的,在你的情况下(如果你可以使用标准的C ++ 14)可以与std::bad_function_call关键字一起使用,以实现非常一般的行为,而无需明确使用模板。关闭也能够捕获部分/整个上下文check the reference

让我们看一个例子,其中我创建了两个接收不同参数的lambda和一个非常通用的#include <iostream> #include <functional> double power2(double x) { return x * x; } int power2int(int x) { return x * x; } template <class T, class P> P simspon(std::function<T(P)> f, P x) { return f(x); } int main() { std::function<double(double)> p_power2 = power2; std::cout << simspon<double, double>(p_power2, 2.0); std::function<double(double)> p_power2int = power2int; std::cout << simspon<int, int>(power2int, 2); return 0; } 函数(实际上它不是,编译器定义了不同的函数)你做的电话。)

auto

您需要使用simpson标志进行编译。我想到了很多建议,建议您避免以这种方式实现您的代码,请记住它只有一些说明性的目的(我用#include <iostream> auto lambda = [](auto x) { return x * x ; }; auto lambda_2 = [] (int x) { return x + 10; }; auto simpson(auto f, auto x) { return f(x); } int main() { std::cout << simpson(lambda, 2.0); std::cout << simpson(lambda_2, 1); return 0; } 关键字夸大了)。

函数对象(问题类)

对你的情况来说,改进可能就是为数学函数编写一个通用类来集成并将对象传递给你的函数。这带来了几个优点:您可能希望在函数中保存一些综合结果,甚至可以编写流操作符来打印您的问题。这是数学图书馆通常采用的解决方案。

在这个非常简单的案例中,我们有一个问题的类。为此类创建新实例时,-std=c++14将传递给构造函数并存储在类中。类的实例是auto的参数:

std::function

答案 1 :(得分:0)

使用std::function,例如:

#include <iostream>     // std::cout
#include <functional>   // std::function

int main()
{
    std::function<double(double)> simpson_int =([](double x) { return x * x; };
    std::cout << "simpson_int(4): " << simpson_int(4) << '\n';
    return 0;
}

输出:

  

simpson_int(4):16