Pointer to memberfunction of an object

Hello!

I would like to integrate a function with gsl. Therefor I have to define a function f (the integrant, which has to be of the form double (*)(double, void*)). For the call of the gsl integration method I need to define a struct, which contains a pointer to a function (this struct is called gsl_function).

1
2
gsl_function F;
F.function = &(this->f);


The function f must be implemented in a class (in the same class from which the integration procedure should be called). How can I assign the pointer above correctly, since the 2nd line is not compile and leads the error:
ISO C++ forbids taking the address of a bound member function to form a pointer to member function. Say ‘&MyClass::f’
cannot convert ‘double (MyClass::*)(double, void*)’ to ‘double (*)(double, void*)’ in assignment.

How should the correct assignment be stated?

Thanks in advance.


LP
For this class
1
2
3
struct A{
    T f(T2);
};
you get a pointer to A::f() by doing T(A::*)(T2) pointer=&A::f;

I can never remember that syntax.
Last edited on
Sorry I don't understand what you mean or how this would work. What is that struct for and what do you mean with T, T2 (templates? what for?)

Could you please explain this in more detail? Thank you very much!
A, T, and T2 are just placeholders. I put them there so you can see how to get the pointer to function for a struct/class named A with a method named f() which takes a T2 and returns a T. You're supposed to replace the placeholders with your own identifiers.
Last edited on
So then it is exactly the same thing as i wrote above, but using the class name instead of the this pointer.

But my problem is, that I need a pointer to double (*)(double, void*), but just get from my class a pointer to double (MyClass::*)(double, void*), which is not the same.

My question is, what I have to do to assign my function f (defined in MyClass, hence the pointer is of type double (MyClass::*)(double, void*)) to a gsl_function (which is of type double (*)(double, void*)).
I don't think such a cast is possible, but even if it was, it wouldn't be safe. You have a design problem if you need to do something like that.
How could it be done in an other way?

I have to call gsl functions (which are written in c) from a c++ class. And I need to pass a function pointer of the form double (*)(double, void*). How can i manage this?
Sounds like a classic callback function. You typically just write a function specifically for the job. The void * parameter may be for you to pass data for the function to use (or it may be used by library, I don't know).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
double f_callback(double a,void *param){
	your_data *data=(your_data *)param;
	//do stuff
	return /*double*/;
}

void your_function(){
	//...
	your_data data;
	//initialize data
	
	//In this example, you want to call library_function(), which is declared
	//double library_function(double(*callback)(double,void *),void *user_data);
	library_function(&f_callback,&data);
	//...
}
The reason you can't do such a cast is because member functions require an implicit additional parameter for the 'this' pointer.

double (MyClass::*)(double,void*) really gets compiled to something similar to double (*)(MyClass*,double,void*) Therefore you can't simply cast from a member function to a nonmember function (unless the member function is static -- in which case there is no this pointer).

C callbacks typically provide a void* parameter from which you can pass your own user data. From the looks of it, you have this ability here as well. A possible solution here is to pass the 'this' pointer as part of that void* parameter. Here's an example to illustrate:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct CCallbackHolder
{
  MyClass* cls;
  void* data;
};

class MyClass
{
public:
  static double CCallback(double d,void* v)
  {
    CCallbackHolder* h = static_cast<CCallbackHolder*>(v);
    return h->cls->DoCallback(h->data);
  }

  double DoCallback(double d,void* v)
  {
    // do normal callback operation
  }
};


With this, you can give &MyClass::CCallback as the function pointer to the C routine (which will work because it is a static function and therefore does not take a 'this' pointer). The catch is the void* user data you supply to the C routine needs to be encased in that CCallbackHolder struct along with the pointer to the MyClass object you want to call.
Thank you very much! This seems to work. I just assumed that DoCallback in line 13 gets both parameters (d, h->data).

But I don't get one point: What does this static_cast and especially the argument (v) mean?

static_cast<CCallbackHolder*>(v);
Last edited on
That casts the 'v' pointer from generic and not-directly-usable type void* to specific and easily-usable type CCallbackHolder*. It's basically the same idea as a C-style cast: h = (CCallbackHolder*)v;, but is the "C++ way" of doing it (it is benefitial to use static_cast over C-style casting for various reasons -- however none of those reasons really apply when dealing with void pointers, so use whichever you prefer)

void* is basically a very, very ugly generic pointer that says "this pointer points to something, but the compiler has no idea what. It could be pointing to anything". They're used a lot in C because they're generic and because C doesn't offer the more typesafe generic programming techniques that C++ does.

void*s can be dangerous because they require you to explicitly cast them to something else in order for them to be used, but there is no way to confirm that they really do point to whatever you're trying to cast them to. For example:

 
CCallbackHolder* h = static_cast<CCallbackHolder*>(v);


This works as long as 'v' points to a CCallbackHolder object. If v points to some other type, you won't get any compiler warning/error, but the program will totally screw up. These kinds of bugs are very hard to track down sometimes.

So yeah -- avoid void* like the plague. I only used them in this example because your callback seemed to require it. If the C code you're working with is using void*s, then I guess you're stuck.
Last edited on
Thank you very much for your help!
Topic archived. No new replies allowed.