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

Posted

技术标签:

【中文标题】指向具有多个参数作为函数参数的函数的指针【英文标题】:Pointers to functions with multiple arguments as function arguments 【发布时间】:2014-11-03 05:32:02 【问题描述】:

我使用优化工具箱中的一个函数,该函数以数值方式计算函数的导数。它接受一个指向带有一个参数的函数的指针,但是如果我需要将一个指向带有多个参数的函数的指针传递给它,并期望只传递额外的、不太重要的参数呢?

//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_differentiation 以便在调用 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/)。

【问题讨论】:

要在编译时执行此操作,您可以使用可变参数模板。不过,我不确定 VS2013 对此的支持有多好。 【参考方案1】:
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::anystd::function[](double d) return d; ; register_callback(&wrap_legacy, &fun);

当然,一般来说,client_data 生命周期要求指向堆分配,因此您需要处理它。你还可以做进一步的包装,比如包装register_callback--这样可以提高安全性。

【讨论】:

谢谢,给我一个 +1。我上面的解决方案非常受您的第一个建议的启发。我没有完全得到第二个,或者它对我来说太麻烦了,因为我必须将整个算法放入这些本身就是函数参数的大括号中。 您包装 std:function 的解决方案非常有趣,但是对我自己的函数 my_func_to_be_input 的调用到底是在哪里输入的?也可以将这样的 wrap_legacy 包装器推广到所有类型的 (a) 遗留函数(如您的 register_callback)和 (b) 具有多个要传递的参数的客户端函数(如 my_func_to_be_input)?【参考方案2】:

一个设计良好的 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);

【讨论】:

请注意,精心设计的 C++ 工具箱的风格完全不同,但许多数字工具箱是 C 而不是 C++,而且您的代码肯定使用 C 风格库。 所讨论的工具箱确实是 Numerical Recipes 2.1,尽管它们使用命名空间和 C++ 的其他特性,但它非常类似于 C。我不确定最新的版本 3 在这方面是否更好。 我给了你 +1 提醒我如何以老式 C 方式进行操作。

以上是关于指向具有多个参数作为函数参数的函数的指针的主要内容,如果未能解决你的问题,请参考以下文章

具有在参数中返回指针的函数的智能指针

使用变量与指向变量的指针作为函数的参数

指向继承类实例的指针作为函数参数

C - 尝试将指向函数的指针作为参数传递时出错,无法获取值

指向类方法的函数指针作为参数

C++ 使用指向相同函数的指针作为模板参数是不是总是会导致相同的实例化?