Sign in to follow this  

error C3867 - trying to pass member function as parameter

This topic is 2956 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have this class, in the constructor I want to start a suspended thread ( calling CreateThread(..) that receives a pointer to the function that will be the thread execution code ).. That threadfunc is a member function of this same class, VS is complaining about it, and says to me to use &class::threadfunc instead of the usually just threadfunc.. The problem is when I do it, it says theres no possible conversion between 'DWORD (__thiscall Scheduler::* )(LPVOID)' to 'LPTHREAD_START_ROUTINE' .. What can I do? The constructor:
Scheduler::Scheduler(){

	//
	uiTempoGlobal = 0;
	uiTempoNextEvent = 0;
	//-------------------

	//
	hStartSimulThread = CreateThread(NULL,0,&Scheduler::StartSimulThread,NULL,CREATE_SUSPENDED,NULL);
	//just StartSimulThread doesnt work
	//---------------------------------------------------
...

The class:

class Scheduler{

public:
	 Scheduler();
	~Scheduler();

...

...

	DWORD StartSimulThread( LPVOID lpDatap );
		HANDLE hStartSimulThread;



Share this post


Link to post
Share on other sites
A pointer to a member function isn't the same as a pointer to a normal function. If you want to use a member function as a thread you need to use a non-member or static function as a trampoline to the member function. Something like:

DWORD trampoline(void * data) {
return (static_cast<Scheduler>(data)->StartSimulThread)();
}

Note that StartSimulThread() will no longer need a void pointer argument.

Share this post


Link to post
Share on other sites
Thats so confuse to me..Let me see if I get it..
You have to use a trampoline, because member function pointers are like inexistent, but I still need a member function because it mess with the actuall object(Scheduler's) data, so I just need a normal function that receives the entire object as parameter..thats it?

@.@
why the static_cast btw?




Share this post


Link to post
Share on other sites
Quote:
Original post by Icebone1000
because member function pointers are like inexistent


Pointers to member functions have the wrong type.

The library wants a DWORD(*)(void*).

The member function is a DWORD(Scheduler::*)(void*).

The type is different because member functions are called differently from normal functions. They need an instance of the class to be called upon. There is no way that the function pointer can say which instance to use.

Quote:
so I just need a normal function that receives the entire object as parameter..thats it?

@.@
why the static_cast btw?


The library expects a DWORD(*)(void*) so that you can pass whatever data you like by making the void* point at it. (This way, it doesn't have to think about the type of the data that your function needs: it just takes your callback function and a void* pointing to your data, does the magic to make a new thread, and makes the new thread call the callback function with the data).

This gives us a clever trick that we can use to run a member function. We use the void* to point at an instance of the class, and write the callback so that it calls the member function. We need a static_cast because the callback takes in a void*, and we have to tell the compiler that it actually points at an instance of the class.

Put together, it all works like:


class Scheduler{

public:
Scheduler();
~Scheduler();

...

...
// StartSimulThread doesn't need any arguments, so we don't pass any.
DWORD StartSimulThread();
HANDLE hStartSimulThread;

...

Scheduler::Scheduler(){

//
uiTempoGlobal = 0;
uiTempoNextEvent = 0;
//-------------------

// We pass the pointer to the current instance ('this') as the data
// for the callback, and the trampoline as the callback.
hStartSimulThread = CreateThread(NULL,0,trampoline,this,CREATE_SUSPENDED,NULL);
//---------------------------------------------------
...

// This is not a member function.
DWORD trampoline(LPVOID data) {
// The void* actually points at some instance of Scheduler, as above.
// So here we make the cast, and call the member function. I'll show
// it in 2 lines; is it clearer now?
Scheduler* scheduler = static_cast<Scheduler*>(data);
return scheduler->StartSimulThread();
}

Share this post


Link to post
Share on other sites

This topic is 2956 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this