Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;:以任意数量的参数作为参数的传递函数_C++_Templates_Function Pointers_Functor - Fatal编程技术网

C++ C++;:以任意数量的参数作为参数的传递函数

C++ C++;:以任意数量的参数作为参数的传递函数,c++,templates,function-pointers,functor,C++,Templates,Function Pointers,Functor,长时间浏览,第一次在这里询问。我已经编写了许多脚本来执行各种一维数值积分方法,并将它们编译成一个库。我希望该库在能够集成什么方面尽可能灵活 这里我包括一个示例:一个非常简单的梯形规则示例,其中我传递一个指向要集成的函数的指针 // Numerically integrate (*f) from a to b // using the trapezoidal rule. double trap(double (*f)(double), double a, double b) { int N =

长时间浏览,第一次在这里询问。我已经编写了许多脚本来执行各种一维数值积分方法,并将它们编译成一个库。我希望该库在能够集成什么方面尽可能灵活

这里我包括一个示例:一个非常简单的梯形规则示例,其中我传递一个指向要集成的函数的指针

// 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;
}
然而,有时我可能想积分一些有更多参数的东西,比如二次多项式。在此示例中,系数将由用户在积分之前定义。示例代码:

// arbitrary quadratic polynomial
double quad(double A, double B, double C, double x) {
  return (A*pow(x,2) + B*x + C);
}
理想情况下,我可以这样做来整合它:

double b = trap(quad(1,2,3),0,1);
但很明显,这是行不通的。我通过定义一个类来解决这个问题,该类的系数为成员,感兴趣的函数为成员函数:

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); }
};
但是,我的集成函数需要更改,以将对象作为输入,而不是函数指针:

// 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;
}
//将model.func从a数值积分到b
//使用梯形法则。
双陷阱(模型多边形、双a、双b){
int N=10000;
双步骤=(b-a)/N;
双s=0;

对于(int i=0;i您需要的是模板和
std::bind()
(或者如果您负担不起C++11,它的
boost::bind()
对应项)。例如,这就是您的
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;
}
现在,您可以直接在
trap()
的输入中提供第一个函数,或者将第二个函数的最后三个参数绑定到某个特定值的结果(您可以自由选择绑定哪些参数):

#包括
int main()
{
陷阱(foo,0,42);
trap(std::bind(bar,std::占位符::1,421729,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; // 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
}
#包括
#包括
int main()
{
陷阱(foo,0,42);
trap(std::bind(bar,std::占位符::1,421729,0),0,42);
int x=1729;//或某些计算的结果。。。
int y=42;//或某些特定的状态信息。。。
陷阱([&](双d)->双
{
x+=42*d;//或一些有意义的计算。。。
y=1;//或某个有意义的操作。。。
返回x;
}, 0, 42);

std::cout您需要的是模板和
std::bind()
(或者如果您负担不起C++11,它的
boost::bind()
对应物)。例如,这就是您的
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;
}
现在,您可以直接在
trap()
的输入中提供第一个函数,或者将第二个函数的最后三个参数绑定到某个特定值的结果(您可以自由选择绑定哪些参数):

#包括
int main()
{
陷阱(foo,0,42);
trap(std::bind(bar,std::占位符::1,421729,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; // 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
}
#包括
#包括
int main()
{
陷阱(foo,0,42);
trap(std::bind(bar,std::占位符::1,421729,0),0,42);
int x=1729;//或某些计算的结果。。。
int y=42;//或某些特定的状态信息。。。
陷阱([&](双d)->双
{
x+=42*d;//或一些有意义的计算。。。
y=1;//或某个有意义的操作。。。
返回x;
}, 0, 42);

std::cout你想做的就是让这成为可能

trap( quad, 1, 2, 3, 0, 1 );
在C++11中,我们有别名模板和变量模板

template< typename... Ts >
using custom_function_t = double (*f) ( double, Ts... );
用法:

double foo ( double X ) {
  return X;
}

double quad( double X, double A, double B, double C ) {
  return(A*pow(x,2) + B*x + C);
}

int main() {
  double result_foo  = trap( foo, 0, 1 );
  double result_quad = trap( quad, 1, 2, 3, 0, 1 );  // 1, 2, 3 == A, B, C respectively
}

在Apple LLVM 4.2编译器上测试。

您要做的就是使之成为可能

trap( quad, 1, 2, 3, 0, 1 );
在C++11中,我们有别名模板和变量模板

template< typename... Ts >
using custom_function_t = double (*f) ( double, Ts... );
用法:

double foo ( double X ) {
  return X;
}

double quad( double X, double A, double B, double C ) {
  return(A*pow(x,2) + B*x + C);
}

int main() {
  double result_foo  = trap( foo, 0, 1 );
  double result_quad = trap( quad, 1, 2, 3, 0, 1 );  // 1, 2, 3 == A, B, C respectively
}

在Apple LLVM 4.2编译器上测试。

谢谢!我确实喜欢模板示例,因为它非常优雅,但我不确定它是否适合我-我的理解是,模板函数必须在同一位置定义和声明,而我想定义
trap()
在一个单独的库中,然后声明它用于其他项目。我接受了您的建议,将
std::function
std::bind
结合使用,并将
trap()
重新定义为
双陷阱(std::function f,double a,double b)
;唯一令人恼火的是,我必须将像sin这样的简单函数重新定义为
std::function
@t354:是的,模板存在分离问题:定义必须在头文件中。或者,您可以将定义放在
.cpp
文件中,并提供模板的所谓显式实例化对于应用程序中使用的所有可能参数,如果您的是一个库,则无法预测模板将如何实例化。将
std::function
放入签名中是可以的:请注意存在运行时开销,因此您必须衡量它是否与您相关。@t354:我知道不理解最后一部分:你说的“重新定义像
sin
这样的简单函数”是什么意思?如果你的意思是:
std::function=sin;trap(sin,0,42);
,那么它就不需要了。你可以直接调用
trap(sin,0,42);
,而不用声明
std::function
对象。如果我已经定义了
双陷阱(std::function f,double a,double b)
我试图调用
trap(sin,0,42);
正如您所建议的,我得到一个错误:
error:从“”转换为请求的非标量类型“std::function”
。我可以通过重新定义sin:
std::function f_sin=(double(*)(double))来避免这种情况&std::sin;
关于您在第一条评论中提到的运行时开销,使用lambda会比我当前的解决方案更有效吗?我对它们不太熟悉,但可能值得付出努力。@t354:哦,那是因为它实际上是一个重载函数(有一个
float
版本,一个
双精度)