function point of class function

R

Ralf Goertz

Hi,

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. If
"eval" is declared outside foo it works fine. 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. Why is it
not allowed to do it in the intended way and what would be a good work
around?

Ralf
 
B

Barry

Hi,

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. If
"eval" is declared outside foo it works fine. 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. Why is it
not allowed to do it in the intended way and what would be a good work
around?

here foo::eval is typeof "void (foo::*)(double*, double*)"
not "void (*)(double*, double*)".

the former one is pointer to member funtion,
the latter is pointer to function.
they are different.

to patch your code, make foo::eval a static member function.
 
R

Ralf Goertz

Barry said:
here foo::eval is typeof "void (foo::*)(double*, double*)"
not "void (*)(double*, double*)".

the former one is pointer to member funtion,
the latter is pointer to function.
they are different.

to patch your code, make foo::eval a static member function.

The problem is I can't do that since foo::eval is useless with a default
ctor.
 
J

James Kanze

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.)
 
R

Ralf Goertz

James said:
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.

On second thought I came to that conclusion myself.
You also have to declare it `extern "C"' is you have a
conformant compiler. Language linkage is part of the type.




An important point here is that globally defined pointer. You
can't call eval without it.

Yes I see that now.
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 ) ;

That's the way it is defined, I just left out the userData in my
example.
And your global function would be:

extern "C" void
wrapper( double* p, double* hx, void* userData )
{
static_cast< foo* >( userData )->f( p, x ) ;
}

Again, I figured that out myself. It somehow pays off to be lurking
around.
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.)

Oh thanks, as you say, g++ didn't bark at me. But I thought that a
function that is explicitely declared as a C function can't call a
C++-function.

Ralf
 
J

James Kanze

On Mar 5, 3:16 pm, Ralf Goertz

[...]
Oh thanks, as you say, g++ didn't bark at me. But I thought
that a function that is explicitely declared as a C function
can't call a C++-function.

You're still compiling in C++. A function declared `extern "C"'
is a C++ function, and can be (and in fact must be, if its
definition is in a C++ source file) written in C++, using all of
the facilities of C++. The only difference is the way the
compiler generates its interface: if the function is `extern
"C"', the compiler generates the interface (function name,
calling conventions, etc.) as if it were a C function. (On most
platforms today, C and C++ use the same calling conventions, but
there's no real reason that this should be the case, and I've
used a compiler on Intel where they didn't.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,176
Messages
2,570,950
Members
47,503
Latest member
supremedee

Latest Threads

Top