Solution for function passing with external variables


windmaomao
12-10-2004, 12:43 PM
I am not sure if anyone has already posted it but i am sure it's not new to lot of programmers.

For example, if you want to integrate arbitary function, you define a function type float (*func)(float), and you pass it to your integration algorithm. This is very general and easy approach except that when you need to pass extra variables into the algorithm. This is when trouble starts. Usually, as NR does, we define a GLOBAL variable.

But no insult to fortran people, this global variable approach is very bad design.

Recently i just found there's a better way doing this by using the Boost::function and Boost::bind. Here's one example

#include <iostream>

#include <boost/function.hpp>
#include <boost/bind.hpp>

class A {
public:
float constant;
A(): constant(0.2) {}
float func(A* a, float x) { return a->constant+x; }
};

int main()
{
using namespace std;

boost::function<float (A*,float) > f;
A a;
f=boost::bind(&A::func,&a,_1,_2);

cout << f(&a, 0.3);

int b;
cin >> b;

return 0;
}

For clarity, the idea is that now you can use f to call any function (has to be declared type) inside any class or struct and at the same time be able to access the data inside that class.

For more example, check the manual in http://www.boost.org/libs/libraries.htm


Best regards
Fang

windmaomao
12-10-2004, 02:35 PM
Hope the following helps

#include <iostream>
#include "fjlib_integration.h"

using namespace fjlib;


float_t func_test1(void* obj, float_t* x)
{

return 2.0*(*x)*(*x)+1;
}

struct func_class {
float_t func_test2(void* obj, float_t* x)
{
return func_test1(obj,x);
}
float_t b;
float_t func_test3(void* obj, float_t* x)
{
return func_test1(obj,x)*b;
}
float_t func_test4(void* obj, float_t* x)
{
TFJIntegrate_Trapzd *t=(TFJIntegrate_Trapzd *)obj;
return func_test1(obj,x)*t->nseg;
}
};

int main()
{
using namespace std;
TFJIntegrate_Trapzd integ1;

integ1.function=func_test1;
cout<<integ1.integrate(0,1,20) << endl;

func_class fc;
integ1.function=boost::bind(&func_class::func_test2,
&fc,_1,_2);
cout<<integ1.integrate(0,1,20) << endl;

fc.b=2.0;
integ1.function=boost::bind(&func_class::func_test3,
&fc,_1,_2);
cout<<integ1.integrate(0,1,20) << endl;

integ1.function=boost::bind(&func_class::func_test4,
&fc,_1,_2);
integ1.nseg=2;
cout<<integ1.integrate(0,1,20) << endl;

int j;
cin >> j;

return 0;
}

pdespres
03-15-2005, 06:24 PM
Hello,

your solution looks interesting. Actually, I would like to pass member function to certain NR routines, like

void mrqmin(Vec_I_DP &x, Vec_I_DP &y, Vec_I_DP &sig, Vec_IO_DP &a,
Vec_I_BOOL &ia, Mat_O_DP &covar, Mat_O_DP &alpha, DP &chisq,
void funcs(const DP, Vec_I_DP &, DP &, Vec_O_DP &), DP &alamda)


The problem is that member functions do not have the signature corresponding to the funcs argument in mrqmin. It is possible to declare the member function as static but then you don't have access to the class variables... I do not want to use global variables. I guess that Boost can do the job here. Is it possible for you to post your file fjlib_integration.h?

Thanks,
Philippe