指向具有多个参数作为函数参数的函数的指针

Pointers to functions with multiple arguments as function arguments

本文关键字:函数 参数 指针      更新时间:2023-10-16

我使用优化工具箱中的一个函数来数值计算函数的导数。它接受指向带有一个参数的函数的指针,但如果我需要将指向带有多个参数的功能的指针传递给它,并期望传递其他不太重要的参数,该怎么办?

//Function from toolbox
double num_differentation(double (func(const double)), double x)
{
//makes various calls to func, but with only one parameter
func(x);
}

现在假设我有一个函数,我想传递给上面的函数,但它有额外的参数,与优化问题没有直接关系,但仍然需要这些参数才能为函数得出有意义的结果。

double my_func_to_be_input(double a, double b, double c) {
return a+b*c;
}

有没有办法重写num_differentialion,以便在调用func时通过所有三个参数?我尝试了以下操作,但没有成功:

double num_differentation(double (func(const double arg1, const double arg2, const double arg3)), double x)
{
//makes various calls to func, but with only one parameter
func(x, arg2, arg3);
}

如果我们想更花哨一点,num_differentiation是否有可能接受一个具有不同数量参数的函数,而不相关的参数只是通过?

在任何情况下,我都不想求助于全局变量来路由这些额外的参数。

我使用的是Visual Studio 2013,欢迎任何有用的建议,尤其是具体的代码示例。

更新:这就是我解决问题的方法。

//Rewritten function from toolbox
double rewritten_num_differentation(std::function<double(double)> func, double x)
{
func(x);
}

在我的主代码中:

using namespace std::placeholders;    
auto my_func_to_be_input_with_forwarded_arguments= std::bind(my_func_to_be_input, _1, second_argument_to_be_forwarded, third_argument_to_be_forwarded);
return rewritten_num_differentiation(my_func_to_be_input_with_forwarded_arguments, x_arg);

这类似于CrazyEdie提出的第一个解决方案。也许还有一些更优雅的方法不需要重写工具箱函数,但将std::function类型转换为C风格的函数指针似乎非常复杂(就像他们在这里尝试的那样http://www.cplusplus.com/forum/general/63552/)。

double num_differentials(std::function<double(double)> fun, double x)
{
    return fun(x);
}
auto n = num_differentials(std::bind(&fun, _1, arg1, arg2), x);

或者:

auto n = num_differentials([arg1,arg2](double x) { return fun(x,arg1,arg2); }, x);

我认为两者都应该在VC2013工作。

编辑以响应更新:

通过C回调系统调用std::function并不难。

假设:

void register_callback(double (*fun)(double,void*), void* client_data);

写下:

double wrap_legacy(double d, void* client_data)
{
    auto fun = static_cast<std::function<double(double)>*>(client_data);
    return (*fun)(d);
}

或者,如果你想增加一些安全性,这个:

double wrap_legacy(double d, void* client_data)
{
    auto any = static_cast<boost::any*>(client_data);
    auto fun = boost::any_cast<std::function<double(double)>>(*any);
    return fun(d);
}

在这里,您只需将boost::any用作任何和所有此类构造的标准类型。始终投射到任意,并始终包裹在任意中。然后,如果有人搞砸了,发送了错误的数据,你会得到异常,而不是未定义的行为。

像这样使用:

auto fun = std::function<double(double)>{[](double d) { return d; }};
register_callback(&wrap_legacy, &fun);

或者安全版本:auto-any=boost::any{std::function{[](double d){return d;}};register_recallback(&wrap_legacy,&fun);

当然,一般来说,client_data生存期要求指向堆分配,所以您需要处理这个问题。你还可以做进一步的包装,比如包装register_callback,这可以提高安全性。

一个设计良好的C风格工具箱的原型是:

//Function from toolbox
double num_differentation(double (func(const double, void*)), 
                          double x, 
                          void * user_data)
{
 //makes various calls to func, but with only one parameter
 func(x, user_data);
}

然后期望用户编写

typedef struct my_data { int p; } my_data
double func(double x, void * user_data) {
   my_data * data = (my_data*)user_data;
   return pow(x, data->p);
}

你可以这样使用图书馆:

my_data data;
data.p = 7;
num_differentiation(&func, 3.0, &data);

然而,这听起来像是你被一个讨厌的工具箱卡住了,"标准"是使用全局,而不是传递用户数据。

my_data g_data;
double func(double x) {
   return pow(x, g_data.p);
}

然后像一样使用

g_data.p=7;
num_differentiation(&func, 3.0);