passing a pointer to member function problem

D

dice

Hi,
In order to use an external api call that requires a function pointer I
am currently creating static wrappers to call my objects functions.
I want to re-jig this so I only need 1 static wrapper function.
I would prefer to be able to pass the member function as a void* to the
static wrapper but I suspect this may not even be possible.
Another solution would be option 2 below but I can't figure out the
syntax to call obj->*pFn().

Thanks in advance for any suggestions / observations.

typedef void (*ExecFn)(void *);

void external_api_fn(ExecFn fn,void* p)
{
fn(p);
}

class Doit
{
public:
void fn1(void){printf("fn1\n");}
void fn2(void){printf("fn2\n");}
//current solution
static void static_wrapper1(void *obj)
{
((Doit*)obj)->fn1();
}
static void static_wrapper2(void *obj)
{
((Doit*)obj)->fn2();
}
//option 1
static void static_wrapper3(void *fn)
{
//fn();
}
//option 2
void (Doit::*pFn)(void);
static void static_wrapper4(void *obj)
{
//execute pFn - obj->*pFn - how to execute pFn for obj?
}
//--
Doit()
{
//what Im doing
external_api_fn(static_wrapper1,this);
external_api_fn(static_wrapper2,this);
//option 1 - cast fn1 to void?
//external_api_fn(static_wrapper3,fn1);
//external_api_fn(static_wrapper3,fn2);
//option 2
pFn = fn1;
external_api_fn(static_wrapper4,this);
pFn = fn2;
external_api_fn(static_wrapper4,this);
}
};
 
S

Stuart Redmann

dice said:
Hi,
In order to use an external api call that requires a function pointer I
am currently creating static wrappers to call my objects functions.
I want to re-jig this so I only need 1 static wrapper function.

The problem is that you need to pass the 'this' pointer to the function.
I would prefer to be able to pass the member function as a void* to the
static wrapper but I suspect this may not even be possible.

As a matter of fact, taking the address of a method is possible, but
wouldn't solve your problem, since you need to pass the 'this' pointer
as well (so you actually have to pass _two_ parameters to the function).
Another solution would be option 2 below but I can't figure out the
syntax to call obj->*pFn().

Of course. You don't have the 'this' pointer.
typedef void (*ExecFn)(void *);

void external_api_fn(ExecFn fn,void* p)
{
fn(p);
}

class Doit
{
public:
void fn1(void){printf("fn1\n");}
void fn2(void){printf("fn2\n");}
//current solution
static void static_wrapper1(void *obj)
{
((Doit*)obj)->fn1();
}
static void static_wrapper2(void *obj)
{
((Doit*)obj)->fn2();
}
//option 1
static void static_wrapper3(void *fn)
{
//fn();
}
//option 2
void (Doit::*pFn)(void);
static void static_wrapper4(void *obj)
{
//execute pFn - obj->*pFn - how to execute pFn for obj?
}
//--
Doit()
{
//what Im doing
external_api_fn(static_wrapper1,this);
external_api_fn(static_wrapper2,this);
//option 1 - cast fn1 to void?
//external_api_fn(static_wrapper3,fn1);
//external_api_fn(static_wrapper3,fn2);
//option 2
pFn = fn1;
external_api_fn(static_wrapper4,this);
pFn = fn2;
external_api_fn(static_wrapper4,this);
}
};

How about this:

#include <stdio.h>

typedef void (*ExecFn)(void);

void external_api_fn (ExecFn fn)
{
fn ();
}

class Doit
{
typedef void (Doit::*PtrToMemberForWrapperType) (void);
private:
static Doit* ms_ThisForWrapper;
static PtrToMemberForWrapperType ms_PtrMemberFuncForWrapper;

static void static_wrapper ()
{
// Invoke the member function of the static object.
(ms_ThisForWrapper->*ms_PtrMemberFuncForWrapper) ();
}

public:
void fn1(void) {printf("fn1\n");}
void fn2(void) {printf("fn2\n");}

void call_external_api_fn (PtrToMemberForWrapperType pMemberFunc)
{
// Store away the this pointer.
ms_ThisForWrapper = this;
ms_PtrMemberFuncForWrapper = pMemberFunc;
external_api_fn (&static_wrapper);
}
};

Doit::ptrToMemberForWrapperType Doit::ms_PtrMemberFuncForWrapper = 0;
Doit* Doit::ms_ThisForWrapper = 0;

int main ()
{
Doit MyDoit;
MyDoit.call_external_api_fn (Doit::fn1);

return 0;
}


I took the liberty to change the definition of ExecFn to a function that
takes no arguments, since your members fn1 and fn2 don't take arguments.
The above solution is not intended for use in multi-threaded
applications, since it uses static class members. If you want to use
this in a multi-threaded app, you have to introduce a map that stores
these pointers for each thread that uses the class.

Regards,
Stuart
 
D

dice

Stuart said:
The problem is that you need to pass the 'this' pointer to the function.


As a matter of fact, taking the address of a method is possible, but
wouldn't solve your problem, since you need to pass the 'this' pointer
as well (so you actually have to pass _two_ parameters to the function).

yes - i wasn't quite thinking straight there, but see option 2 - this
is essentially the same thing, pass the 'this' pointer after setting a
function pointer in the object.
Of course. You don't have the 'this' pointer.

'this' is passed as the second arg as per:
external_api_fn(static_wrapper4,this);

I thought that since the following is possible by passing 'this' as
void* obj:
((Doit*)obj)->fn1();
then static_wrapper4 could use something like the following:
(((Doit*)obj)->*pFn)();
How about this:

#include <stdio.h>

typedef void (*ExecFn)(void);

void external_api_fn (ExecFn fn)
{
fn ();
}

class Doit
{
typedef void (Doit::*PtrToMemberForWrapperType) (void);
private:
static Doit* ms_ThisForWrapper;
static PtrToMemberForWrapperType ms_PtrMemberFuncForWrapper;

static void static_wrapper ()
{
// Invoke the member function of the static object.
(ms_ThisForWrapper->*ms_PtrMemberFuncForWrapper) ();
}

public:
void fn1(void) {printf("fn1\n");}
void fn2(void) {printf("fn2\n");}

void call_external_api_fn (PtrToMemberForWrapperType pMemberFunc)
{
// Store away the this pointer.
ms_ThisForWrapper = this;
ms_PtrMemberFuncForWrapper = pMemberFunc;
external_api_fn (&static_wrapper);
}
};

Doit::ptrToMemberForWrapperType Doit::ms_PtrMemberFuncForWrapper = 0;
Doit* Doit::ms_ThisForWrapper = 0;

int main ()
{
Doit MyDoit;
MyDoit.call_external_api_fn (Doit::fn1);

this builds and works on my evC++ compiler, but not with mingw32-g++
return 0;
}


I took the liberty to change the definition of ExecFn to a function that
takes no arguments, since your members fn1 and fn2 don't take arguments.
The above solution is not intended for use in multi-threaded
applications, since it uses static class members. If you want to use

Multi threading is not a problem in this particular instance, but I was
trying to avoid static members for just this reason.
 
S

Stuart Redmann

I think I misunderstood you here. Invokation of member functions is
quite ugly (I had to look it up myself). If you have the object and the
pointer to the member function at hand, you can invoke it with the above
syntax, e.g. obj->*pFn (), but you have to enclose this in parentheses:
(obj->*pFn) ()

A even much simpler solution comes into my mind: Since your API function
can be passed _any_ pointer, why don't we give it a pointer to a struct
containing both the object pointer and the member function pointer?
Something like this:

#include <stdio.h>

typedef void (*ExecFn)(void*);

void external_api_fn (ExecFn fn, void* p)
{
fn (p);
}

class Doit
{
typedef void (Doit::*PtrToMemberForWrapperType) (void);
struct SApiFunctionParameters
{
Doit* m_pThisPointer;
PtrToMemberForWrapperType m_pMemberFunction;
};

private:
static void static_wrapper (void* p_VoidPointer)
{
// Cast the passed pointer to a pointer to a parameter struct.
SApiFunctionParameters* pParameters = (SApiFunctionParameters*)
p_VoidPointer;

// Invoke the passed member function for the passed 'this' pointer.
(pParameters->m_pThisPointer->*pParameters->m_pMemberFunction) ();
}

public:
void fn1(void) {printf("fn1\n");}
void fn2(void) {printf("fn2\n");}

void call_external_api_fn (PtrToMemberForWrapperType pMemberFunc)
{
// Store away the 'this' AND the member function pointer.
SApiFunctionParameters ApiFunctionParameters;
ApiFunctionParameters.m_pThisPointer = this;
ApiFunctionParameters.m_pMemberFunction = pMemberFunc;
external_api_fn (&static_wrapper, &ApiFunctionParameters);
}
};

int main ()
{
Doit MyDoit;
MyDoit.call_external_api_fn (Doit::fn1);

return 0;
}

[snipped previous solution]
this builds and works on my evC++ compiler, but not with mingw32-g++

(*blush*) I work with Visual C 6.0 (at least I have the courage to admit
it). Sorry, I can't help you there.
Multi threading is not a problem in this particular instance, but I was
trying to avoid static members for just this reason.

Luckily, multi-threading will be no problem when you use the struct version.

Regards,
Stuart
 

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

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top