Re: function point of class function
On Mar 5, 9:36 am, Ralf Goertz
<r_goe...@expires-2006-11-30.arcornews.de> wrote:
I have a numerical C library for function fitting. It defines a function
extern "C" void fit(
void (*func) (double *p, double *hx),
double *p, double *x);
and I want to use it in a class
class foo
{
public:
double *par,*val;
...
void eval(double*,double*) {...};
void do_fitting()
{
fit(&eval,par,val); (*)
}
};
However, the compiler complains at line (*) that the standard
doesn't allow function pointers of class functions to be used
in that way.
Non-static member functions. Of course not. To call a
non-static member function, you need an instance of the object
to call it on. Where is the instance that fit is going to use.
If "eval" is declared outside foo it works fine.
You also have to declare it `extern "C"' is you have a
conformant compiler. Language linkage is part of the type.
But I think that's a bad design since everthing should take
place in the class foo. At the moment I use a wrapper function
defined outside foo that just calls foo::eval.
void wrapper(double *p, double *x)
{
f->eval(p,x);
}
where f is a globally defined pointer to an instance of foo. I
consider this a bad design, too, but I don't know how to do it
better.
An important point here is that globally defined pointer. You
can't call eval without it.
Another point is that `fit' is poorly designed. Normally,
whenever you have a "callback" (i.e. pass a pointer to a
function), some provision should be made for passing data
through to the function. In C, the classical solution would be
to add a void*, e.g.:
extern "C" void fit(
void (* func)( double* p, double* hx, void* userData ),
double* p,
double* x,
void* userData ) ;
And your global function would be:
extern "C" void
wrapper( double* p, double* hx, void* userData )
{
static_cast< foo* >( userData )->f( p, x ) ;
}
Far from perfect, but about the best you can do in C. In C++,
historically, the preferred solution was to use a reference to an
abstract base class, rather than a pointer to a function. You
derived from the abstract base class, and passed a reference to
the derived object (which could, of course, contain any data you
wanted, thus not loosing the typing). More recently, the
tendency has been to make functions like fit templates, with a
type parameter to specify the binary operator, and use things
like boost::bind to create the necessary functional objects.
This has the advantage of avoiding the necessity of your
explicitly defining an extra class, just to derive from the
abstract base class, and can result in improved performance---no
virtual function call, and even the possibility of the actual
function call being inlined (which can, in some cases, open up a
wealth of additional optimization opportunities). It has the
disadvantage of requiring the definition of fit to be a
template---with most compilers, this means putting it in a
header file, and suffering all of the consequences of the
additional coupling that this causes.
Why is it not allowed to do it in the intended way
You can only do it the "intended" way. The reason the way you
want is not allowed is because it's impossible to implement. In
reality, you need 3 arguments when you call foo::eval, and fit
will only call it with 2.
and what would be a good work around?
See above. If you can't modify fit (and given that it is
`extern "C"', I'm supposing that this is the case), and it won't
call the function with a third argument, which you provide,
passing it through a variable with static lifetime is about the
only alternative you have. (I just hope you don't have to be
multithreaded.)
Just don't forget to declare the wrapper `extern "C"'. For the
day when you compile with a compiler which isn't broken. (Both
VC++ and g++ are broken in this regard. Sun CC issues an error
message, however.)
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34