首页 > 解决方案 > C++:任意函数作为函数的参数

问题描述

假设我想编写一个通用的数值积分脚本,它采用用户定义的函数并对变量进行积分int x。进一步假设该函数可以调用任意数量的数据列表;例如,假设我希望集成器f_integrator能够集成以下任何内容:

integrand(x)=f(x)

integrand(x)=f(x)*g(x)

integrand(x)=(f(x)+g(x)/h(x))

integrand(x)=pow(f(x),2)*k(x)

然后似乎我们需要它能够只调用一个定义明确的 function,而无需指定该函数需要多少个参数(也许我们需要指定其中的一部分,例如函数必须有一个int x)。如果是这样,那我们该如何实施呢?如果我们应该以另一种方式来做,怎么做?

标签: c++functionvariadic-functions

解决方案


f_integrator如果需要传递未知数量的参数,可以使用可变参数模板

template<typename F, typename... Args >
double f_integrator(F integrand, std::tuple<Args...> const &bounds){
// integrate
} 

允许它处理采用任意参数类型的函数(假设积分是doubletype ,如果需要,还可以为返回类型添加另一个模板参数)。模板参数F扮演函数类型的角色。然后,您可以f_integrator直接调用函数,例如 lambda

 double integral = f_integrate([](double x){return f(x)*g(x);},
                               std::make_tuple(1.0,2.0));

请注意,您可以将任何可调用对象传递给f_integrate,因为可调用对象返回您可以集成的内容。

Usingstd::tuple允许以在函数体中可以处理的方式传递集成区域的边界。当然,如果你考虑非平凡的集成区域,事情会变得更复杂,但你仍然可以通过一个由数组表示的网格Args将集成区域的信息传递给f_integrator.

积分本身是如何执行的则是另一回事,但是在一个又一个参数上迭代积分并不是很有效,如果你想做高维积分,蒙特卡洛积分可能是一个好方法。

这是一个非常通用的解决方案,并且给定一些温和的假设,有更方便的实现方式(编写积分器的主体对于可变参数模板来说并不是很简单)。如果被积函数的所有参数都属于同一类型,我们可以将边界作为法向量传递,例如

template<typename F, typename T>
double f_integrate(F integrand, std::vector<T> const &bounds){
  // integrate, much more convenient
}

现在,您提供的示例只需要一个参数,因此,如果您可以很好地集成一维函数,您可以做得更简单一些。如果您只传递带有单个参数的函数,则不需要可变参数模板,只需

template<typename F, typename T=double>
double f_integrate(F integrand, T const& lower_bound, T const& upper_bound){
   // integrate
}

可能,甚至不需要第二个参数,因为您可能只对实数进行积分(请注意,整数上的积分只是离散和,因此在这种情况下不需要以数字方式执行积分)。


推荐阅读