C ++:以任意数量的参数作为参数的pass函数 [英] C++: pass function with arbitrary number of parameters as a parameter

查看:177
本文介绍了C ++:以任意数量的参数作为参数的pass函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

长时间浏览器,第一次asker在这里。我写了一些脚本来做各种1D数值积分方法,并将它们编译成库。我想让图书馆尽可能灵活地集成它是什么。



这里我包括一个例子:一个非常简单的梯形规则示例,其中我通过

  //数字整合(* f)从a到b 
//使用梯形法则。
double trap(double(* f)(double),double a,double b){
int N = 10000;
double step =(b-a)/ N;
双s = 0;
for(int i = 0; i <= N; i ++){
double xi = a + i * step;
if(i == 0 || i == N){s + =(* f)(xi); }
else {s + = 2 *(* f)(xi); }
}
s * =(b-a)/(2 * N);
return s;
}

这对于只接受一个参数的简单函数非常有用。示例:

  double a = trap(sin,0,1);但是,有时候我可能想集成一些具有更多参数的东西,比如二次多项式。在该示例中,系数将由用户在积分之前定义。示例代码:

  //任意二次多项式
双精度(双A,双B,双C,双精度){
return(A * pow(x,2)+ B * x + C);
}

理想情况下,我可以这样做: / p>

  double b = trap(quad(1,2,3),0,1); 

但是显然不行。我已经通过定义一个具有系数作为成员和感兴趣函数作为成员函数的类来解决这个问题:

  class Model {
double A,B,C;
public:
Model(){A = 0; B = 0; C = O; }
模型(double x,double y,double z){A = x; B = y; C = z; }
double func(double x){return(A * pow(x,2)+ B * x + C); }
};

然而,我的集成函数需要改变以一个对象作为输入而不是一个函数指针:

  //使用梯形规则将model.func从a数值整合到b 
//。
double trap(model poly,double a,double b){
int N = 10000;
double step =(b-a)/ N;
double s = 0;
for(int i = 0; i <= N; i ++){
double xi = a + i * step;
if(i == 0 || i == N){s + = poly.func(xi); }
else {s + = 2 * poly.func(xi); }
}
s * =(b-a)/(2 * N);
return s;
}

这很好,但是结果库不是很独立,类模型定义在某处。此外,理想情况下,模型应该能够改变从用户到用户,所以我不想修复它在头文件。我试图使用函数模板和函数来获得这个工作,但它不是很独立,因为再次,模板应该定义在头文件(除非你要显式实例化,我不这样做)。



所以,总结一下:有没有办法让我的集成函数接受带有可变数量输入参数的任意1D函数,同时仍然保持足够的独立性,成为一个独立的图书馆?提前感谢建议。

解决方案

你需要的是模板和 std :: bind (或其 boost :: bind()对应物如果你买不起C ++ 11)。例如,这是你的 trap()函数将成为:

  template< typename F> 
double trap(F& f,double a,double b){
int N = 10000;
double step =(b-a)/ N;
double s = 0;
for(int i = 0; i <= N; i ++){
double xi = a + i * step;
if(i == 0 || i == N){s + = f(xi); }
// ^
else {s + = 2 * f(xi); }
// ^
}
s * =(b-a)/(2 * N)
return s;
}

注意,我们从函数指针推广,允许任何类型的调用对象(例如包括C ++ 11 lambda)。因此,调用用户提供的函数的语法不是 * f(param)(只适用于函数指针),但只是 f(param)



灵活性,让我们考虑两个硬编码的函数(并假装它们有意义):

  double foo(double x)
{
return x * 2;
}

double bar(double x,double y,double z,double t)
{
return x + y *(z - t);
}

现在,您可以直接在输入中提供第一个函数 trap(),或者将第二个函数的最后三个参数绑定到某个特定值的结果(你可以自由选择要绑定的参数):

  #include< functional> 

int main()
{
trap(foo,0,42);
trap(std :: bind(bar,std :: placeholders :: _ 1,42,1729,0),0,42);
}

当然,使用lambdas可以获得更多的灵活性:

  #include< functional> 
#include< iostream>

int main()
{
trap(foo,0,42);
trap(std :: bind(bar,std :: placeholders :: _ 1,42,1729,0),0,42);

int x = 1729 //或者一些计算的结果...
int y = 42; //或一些特定状态信息...
trap([&](double d) - > double
{
x + = 42 * d; //或者一些有意义的计算。 ..
y = 1; //或一些有意义的操作...
return x;
},0,42);

std :: cout<< y; // Prints 1
}

还可以传递自己的有状态函子tp trap(),或者一些包含在 std :: function :function 如果你买不起C ++ 11)。



这里是一个直播示例


long time browser, first time asker here. I've written a number of scripts for doing various 1D numerical integration methods and compiled them into a library. I would like that library to be as flexible as possible regarding what it is capable of integrating.

Here I include an example: a very simple trapezoidal rule example where I pass a pointer to the function to be integrated.

// Numerically integrate (*f) from a to b
// using the trapezoidal rule.
double trap(double (*f)(double), double a, double b) {
  int N = 10000;
  double step = (b-a)/N;
  double s = 0;
  for (int i=0; i<=N; i++) {
    double xi = a + i*step;
    if (i == 0 || i == N) { s += (*f)(xi); }
    else { s += 2*(*f)(xi); }
  }
  s *= (b-a)/(2*N);
  return s;
}

This works great for simple functions that only take one argument. Example:

double a = trap(sin,0,1);

However, sometimes I may want to integrate something that has more parameters, like a quadratic polynomial. In this example, the coefficients would be defined by the user before the integration. Example code:

// arbitrary quadratic polynomial
double quad(double A, double B, double C, double x) {
  return (A*pow(x,2) + B*x + C);
}

Ideally, I would be able to do something like this to integrate it:

double b = trap(quad(1,2,3),0,1);

But clearly that doesn't work. I have gotten around this problem by defining a class that has the coefficients as members and the function of interest as a member function:

class Model {
  double A,B,C;
public:
  Model() { A = 0; B = 0; C = 0; }
  Model(double x, double y, double z) { A = x; B = y; C = z; }
  double func(double x) { return (A*pow(x,2)+B*x+C); }
};

However, then my integration function needs to change to take an object as input instead of a function pointer:

// Numerically integrate model.func from a to b
// using the trapezoidal rule.
double trap(Model poly, double a, double b) {
  int N = 10000;
  double step = (b-a)/N;
  double s = 0;
  for (int i=0; i<=N; i++) {
    double xi = a + i*step;
    if (i == 0 || i == N) { s += poly.func(xi); }
    else { s += 2*poly.func(xi); }
  }
  s *= (b-a)/(2*N);
  return s;
}

This works fine, but the resulting library is not very independent, since it needs the class Model to be defined somewhere. Also, ideally the Model should be able to change from user-to-user so I wouldn't want to fix it in a header file. I have tried to use function templates and functors to get this to work but it is not very independent since again, the template should be defined in a header file (unless you want to explicitly instantiate, which I don't).

So, to sum up: is there any way I can get my integration functions to accept arbitrary 1D functions with a variable number of input parameters while still remaining independent enough that they can be compiled into a stand-alone library? Thanks in advance for the suggestions.

解决方案

What you need is templates and std::bind() (or its boost::bind() counterpart if you can't afford C++11). For instance, this is what your trap() function would become:

template<typename F>
double trap(F&& f, double a, double b) {
  int N = 10000;
  double step = (b-a)/N;
  double s = 0;
  for (int i=0; i<=N; i++) {
    double xi = a + i*step;
    if (i == 0 || i == N) { s += f(xi); }
//                               ^
    else { s += 2* f(xi); }
//                 ^
  }
  s *= (b-a)/(2*N);
  return s;
}

Notice, that we are generalizing from function pointers and allow any type of callable objects (including a C++11 lambda, for instance) to be passed in. Therefore, the syntax for invoking the user-provided function is not *f(param) (which only works for function pointers), but just f(param).

Concerning the flexibility, let's consider two hardcoded functions (and pretend them to be meaningful):

double foo(double x)
{
    return x * 2;
}

double bar(double x, double y, double z, double t)
{
    return x + y * (z - t);
}

You can now provide both the first function directly in input to trap(), or the result of binding the last three arguments of the second function to some particular value (you have free choice on which arguments to bind):

#include <functional>

int main()
{
    trap(foo, 0, 42);
    trap(std::bind(bar, std::placeholders::_1, 42, 1729, 0), 0, 42);
}

Of course, you can get even more flexibility with lambdas:

#include <functional>
#include <iostream>

int main()
{
    trap(foo, 0, 42);
    trap(std::bind(bar, std::placeholders::_1, 42, 1729, 0), 0, 42);

    int x = 1729; // Or the result of some computation...
    int y = 42; // Or some particular state information...
    trap([&] (double d) -> double
    {
        x += 42 * d; // Or some meaningful computation...
        y = 1; // Or some meaningful operation...
        return x;
    }, 0, 42);

    std::cout << y; // Prints 1
}

And you can also pass your own stateful functors tp trap(), or some callable objects wrapped in an std::function object (or boost::function if you can't afford C++11). The choice is pretty wide.

Here is a live example.

这篇关于C ++:以任意数量的参数作为参数的pass函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆