ubuntu 下使用 C++编程,调用 gsl 积分库,被积函数作为成员函数,定义如下:
double planning::f(double x, void * params) {
double alpha = *(double *)params;
double f = pow(x, 4)*sin(0.3*x + 0.12194239*pow(x, 2));
return f;
}
在另一个成员函数中拷贝该函数指针以调用积分计算函数,如下:
void planning::GpsCallback(const GpsImu7661::ivsensorgps::ConstPtr& in) {
gsl_set_error_handler_off();
gsl_integration_workspace * w= gsl_integration_workspace_alloc(1000);
double result, error;
double expected = -4.0;
double alpha = 1.0;
gsl_function F;
//*****************************//
F.function = &f;
//F.function = &planning::f;
F.params = α
int fanhui = gsl_integration_qags(&F, 0, 82.16478, 0, 1e-7, 1000, w, &result,&error);
if (0 == gsl_integration_qags(&F, 0, 82.16478, 0, 1e-7, 1000,w, &result, &error)){
printf("result = % .18f\n", result);
printf("estimated error = % .18f\n", error);
printf("intervals = %zu\n", w->size);
}
gsl_integration_workspace_free(w);
}
*下语句报错如下: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function.
百度错误之后修改为 F.function = &planning::f;
报错变成了:error: cannot convert ‘ double (planning::)(double, void)’ to ‘ double ()(double, void)’ in assignment
有没有在成员函数中调用过 gsl 函数库的大神,,有什么解决方法吗?
1
MeteorCat 2018-02-05 09:48:38 +08:00 via Android
planning 是类?如果是的话 F.function = &this->f 作为传递一个内部函数指针是会提示非静态,建议试下直接使用用函数方式,或者把 f 设为静态成员
|
2
MeteorCat 2018-02-05 09:53:08 +08:00 via Android
稍等下,我本地测试一下使用方式,看下是否我的方式是否可用
|
3
GeruzoniAnsasu 2018-02-05 10:29:48 +08:00
F.function = [this](double x,void *param){return f(x,param);};
或者 F.function = std::bind(f,this,std::placeholders::_1,std::placeholders::_2); |
4
GeruzoniAnsasu 2018-02-05 10:43:20 +08:00
看报错 F.function 应该是个 callable,比如 std::function<double(double,void*)>之类的东西,构造这种东西要么就用 lambda,要么就 functor (重载了()运算符的类),bind 就是用模板构造一个 functor 的方法,但其实现原理相当相当复杂,特别是,如何使 functor 绑定到类成员函数上。用 lambda 就容易理解得多,闭包捕获是世界上所有能进行 functional programing 的语言都通用的语义,把 this 指针捕获进闭包中,然后返回这个闭包。虽说会多出一层显式的调用 wrapping,不过这个 lambda 几乎一定会被优化掉,所以也不用担心这个问题
|
5
MeteorCat 2018-02-05 10:45:28 +08:00
3 楼正确,请楼主下次代码能否贴全?我在编写测试时代的时候一堆报错,我以为是我库链接问题,排查了一遍库文件;又以为是我库版本太老了,更新一遍链接库;而且`gsl_function`到底是函数指针还是`std::function`,我认为楼主在提问上面还需要审慎一下
|
6
innoink 2018-02-05 11:06:16 +08:00 via Android
非静态成员函数需要一个 this 指针参数,所以实际的函数指针类型要么是 ret classname::func(args)要么是 ret func(this, args),你这么转当然会出错
解决方法:构造一个严格的 double ()(double, void*)(非成员函数,或者静态成员函数),把你的 f 包装进去。 |
7
justou 2018-02-05 11:15:44 +08:00
gsl_function 里 function 的签名必须是 double(double, void*)这样的一个纯 C 函数, 不是任何 C++特有的对象.
struct gsl_function_struct { double (* function) (double x, void * params); void * params; }; typedef struct gsl_function_struct gsl_function ; 毕竟 gsl 是个 C 库 |
8
innoink 2018-02-05 11:18:49 +08:00 via Android
还有,很好奇 double alpha = *(double *)params;这是在干嘛
|
12
MeteorCat 2018-02-05 11:39:15 +08:00
@innoink 我也感觉,我 llvm 编译的开启`-Wunused-variable`的时候也是爆出这个局部 unused,可能是为了隐私而删除掉代码;说实话,我很讨厌这种提问风格,排查问题还需要我们一起来猜某个变量或者某个函数的作用和功能
|
13
lanry 2018-02-05 11:41:59 +08:00
planning::f 定义成 static 方法就 ok 了,看上去也没必要定义成 non-static
|
14
zhouzhou113 OP double alpha = *(double *)params;
double alpha = 1.0; F.params = α 上三句没有具体用到, 源码是 c 编写,想运用到 C++的成员函数中, 除了类 planning,以及这两个成员函数是我自己定义的: double planning::f(double x, void * params) void planning::GpsCallback(const GpsImu7661::ivsensorgps::ConstPtr& in) 函数体中的变量函数都对应 gsl 库 |
15
gnaggnoyil 2018-02-05 12:57:49 +08:00
要是 LZ 对如何把一个 invocable object 给塞进一个函数中这个问题想不明白的话,可以想想标准库中的 std::thread 是怎么实现的……
|
16
innoink 2018-02-05 21:01:35 +08:00
#include <iostream>
#include <stdio.h> #include <stdlib.h> #include <string.h> class base{ public: void test() { printf("void test();\n"); } }; int main(int argc,char **argv) { base b; typedef void (*cfp)(base *); auto x = &base::test; cfp c; memcpy(&c, &x, sizeof(c)); c(&b); } 在标准 c++中将非静态成员函数转成 c 风格(即,不是 b.*x 这种形式)的函数指针的唯一方式(如果有其他方式请告诉我) |
18
Jerrymouse1 2018-02-05 22:08:21 +08:00
将那个 f 方法定义为 static,应该能行
|
19
hackpro 2018-02-06 12:25:17 +08:00
|