C++调用 gsl gsl_integration.h 积分

2018-02-05 09:33:25 +08:00
 zhouzhou113

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 函数库的大神,,有什么解决方法吗?

2615 次点击
所在节点    C
19 条回复
MeteorCat
2018-02-05 09:48:38 +08:00
planning 是类?如果是的话 F.function = &this->f 作为传递一个内部函数指针是会提示非静态,建议试下直接使用用函数方式,或者把 f 设为静态成员
MeteorCat
2018-02-05 09:53:08 +08:00
稍等下,我本地测试一下使用方式,看下是否我的方式是否可用
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);
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 几乎一定会被优化掉,所以也不用担心这个问题
MeteorCat
2018-02-05 10:45:28 +08:00
3 楼正确,请楼主下次代码能否贴全?我在编写测试时代的时候一堆报错,我以为是我库链接问题,排查了一遍库文件;又以为是我库版本太老了,更新一遍链接库;而且`gsl_function`到底是函数指针还是`std::function`,我认为楼主在提问上面还需要审慎一下
innoink
2018-02-05 11:06:16 +08:00
非静态成员函数需要一个 this 指针参数,所以实际的函数指针类型要么是 ret classname::func(args)要么是 ret func(this, args),你这么转当然会出错
解决方法:构造一个严格的 double ()(double, void*)(非成员函数,或者静态成员函数),把你的 f 包装进去。
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 库
innoink
2018-02-05 11:18:49 +08:00
还有,很好奇 double alpha = *(double *)params;这是在干嘛
justou
2018-02-05 11:24:26 +08:00
@innoink 把 void* cast 成 double*, 再解引用
innoink
2018-02-05 11:25:57 +08:00
@justou 但是后面也没用到啊
justou
2018-02-05 11:28:49 +08:00
@innoink 他代码问题, 我猜测是 0.12194239 这个参数 →_→
MeteorCat
2018-02-05 11:39:15 +08:00
@innoink 我也感觉,我 llvm 编译的开启`-Wunused-variable`的时候也是爆出这个局部 unused,可能是为了隐私而删除掉代码;说实话,我很讨厌这种提问风格,排查问题还需要我们一起来猜某个变量或者某个函数的作用和功能
lanry
2018-02-05 11:41:59 +08:00
planning::f 定义成 static 方法就 ok 了,看上去也没必要定义成 non-static
zhouzhou113
2018-02-05 12:04:16 +08:00
double alpha = *(double *)params;
double alpha = 1.0;
F.params = &alpha;
上三句没有具体用到,
源码是 c 编写,想运用到 C++的成员函数中,

除了类 planning,以及这两个成员函数是我自己定义的:
double planning::f(double x, void * params)
void planning::GpsCallback(const GpsImu7661::ivsensorgps::ConstPtr& in)

函数体中的变量函数都对应 gsl 库
gnaggnoyil
2018-02-05 12:57:49 +08:00
要是 LZ 对如何把一个 invocable object 给塞进一个函数中这个问题想不明白的话,可以想想标准库中的 std::thread 是怎么实现的……
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 这种形式)的函数指针的唯一方式(如果有其他方式请告诉我)
innoink
2018-02-05 21:08:02 +08:00
@innoink 当然,memcpy 可以改成*((long*)&c) = *((long*)&x);
Jerrymouse1
2018-02-05 22:08:21 +08:00
将那个 f 方法定义为 static,应该能行
hackpro
2018-02-06 12:25:17 +08:00
建议按照
@GeruzoniAnsasu #3 的做法
否则你需要解决函数指针和类成员变量的签名问题

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/428481

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX