Sign in to follow this  
Tjaalie

Member function pointer calling [WORKING]

Recommended Posts

Dear Thread reader, I had an idea about a class that will allow me to call member functions like they where normal functions. I'm not at my development pc right now so I can't really test this but I tough that maybe one of you guys knows if this might work. Here is a sample:
typedef int (*memfunct)(void* _this, int argument);

class member_function
{
public:
  member_function(void* _class, memfunct funct)
  {
    m_class = _class;
    m_funct = funct;
  }

  int call(int argument)
  {
    return m_funct(m_class, argument);
  }

private:
  void*    m_class;
  memfunct m_funct;
};

class A
{
public:
  int do(int argument)
  {
    std::cout << argument;
    return argument+1;
  }
}

int main()
{
  A aclass;
  member_function afunction(&aclass, (memfunct)A::do);
  
  afunction.call(15);

  return 0;
}


Now my question is, will this work or do I have to do some secret assembly magic? I have a general idea of how that will work. Just pop all arguments (including the this pointer) and then call the function address. But of course it would be nicer if this worked. I will check it out as soon as I get to my dev pc. Ow and I'm using linux so I would compile this with g++. Tjaalie, [Edited by - Tjaalie on August 19, 2009 8:55:02 AM]

Share this post


Link to post
Share on other sites
No that won't work. If it does for testing, then it's just a lucky coincidence.

You can, however, still do that - safely and effectively - via boost::function and boost::bind:

A aclass;
boost::function<int(int)> afunction = boost::bind(&A::foo, boost::ref(A));

afunction(16);

(btw you can't call your function do, that's a keyword)

Edit: Ninja'd. BTW Sc4Freak when you bind, get rid of the () or it looks like you're trying to call the function.

Share this post


Link to post
Share on other sites
Quote:
Original post by nullsquared
Edit: Ninja'd. BTW Sc4Freak when you bind, get rid of the () or it looks like you're trying to call the function.

Ah, yes. Nicely caught. [grin]

Corrected:
boost::function<void()> function = boost::bind(&Foo::Bar, &object);

Share this post


Link to post
Share on other sites
Thank you, I know of the template stuff but I tough it looked nice if that would work. Too bad, I actually found a compiler on this computer and tried some stuff. I was able to get the address of a normal function into a 64 bit integer, but I couldn't get a member functions address. Is this also impossible? I'm just messing around with some idea's it doesn't really have a function yet, but it will as soon as my scripting engine will be capable of calling c++ functions. I rather not use boost because I'm programming for my own fun and want to do everything from scratch, its really fun to reinvent the wheel from a experience point of view. But thanks for your quick responses, that's why I love these forums. So is it possible to get the address of the function into a integer (or void*) I know this is really bad practice.

edit:

this is what I got so far.


//works
unsigned long long functptr = (unsigned long long)&main;

//gives error (renamed do to doit)
unsigned long long functptr = (unsigned long long)&A::doit;

Share this post


Link to post
Share on other sites
Quote:
Original post by Tjaalie
it will as soon as my scripting engine will be capable of calling c++ functions.


That's precisely why you want to use boost. Luabind, which is a C++ bindings library for Lua, makes extensive use of boost. This allows you to mix and match C/C++ functions/member-functions/functors and Lua functions very, very easily.

Share this post


Link to post
Share on other sites
Call me crazy but I got it to work. Here is the totally messy code that shouldn't be used for anything other than experiments like this. I'm not going to use this code because this is probably undefined behaviour that somehow works the way I want it to work.


#include <iostream>

typedef int (*memfunct)(void* _this, int argument);

class member_function
{
public:
member_function(void* _class, void** funct)
{
m_class = _class;
m_funct = (memfunct)*funct;
}

int call(int argument)
{
return m_funct(m_class, argument);
}

private:
void* m_class;
memfunct m_funct;
};

class A
{
public:
int doit(int argument)
{
std::cout << argument;
return argument+1;
}
};

int main()
{
A aclass;
int (A::*funct)(int) = &A::doit;
member_function afunction(&aclass, (void**)&funct);

afunction.call(15);

return 0;
}




It prints '15' when compiled using g++. Maybe someone dares to try this with visual studio, just to see if it works.

edit:
I tried the code with member variables in the class A. Everything seems to work just as expected. If I can find a way to cleanly convert the member function to a void** without the need of the extra variable I might be able to actually use this. Although maybe not the smartest thing to do but it seems to work.

Share this post


Link to post
Share on other sites
With VC 2005 your code outputs 1245027. It seems that you are making some unsafe assumptions about how a member function call happens.

It outputs 15 if you explicitly specify __stdcall as calling convention:


class A
{
public:
int __stdcall doit(int argument)
{
std::cout << argument;
return argument+1;
}
};

int main()
{
A aclass;
int (__stdcall A::*funct)(int) = &A::doit;
member_function afunction(&aclass, (void**)&funct);

afunction.call(15);

return 0;
}



All in all, it looks like a very fragile hack.

Share this post


Link to post
Share on other sites
haha, funny.
I don't think I will be using this. The only way to make this work in a way that I think has some nice notation is with a marco from hell.

Share this post


Link to post
Share on other sites
You don't want to cast a member function to void* or anything like that, this behavior is undefined by the standard because member function pointers could be different sizes with different compilers etc. its not going to be pretty...

Don't listen to people telling you what you WANT to use if you don't want to use it. I think this community is breeding a generation of game scripters, rather than programmers who understand the low level intricacies of the language they're using.

You're kinda on the right track with what you're trying to do. This code should give you an idea of how to properly bind a member function. But for full support of multiple arguments/parameters i would recommend you look into how luaPlus does its binding, you can download their callback dispatcher as a package on its own, but its quite template heavy and hard to understand for a beginner (and theres a couple of bugs in it).

Anyhow, here is how you bind a member function that takes an int and returns a bool:

class cDispatcher
{
public:
virtual bool dispatch ( int x ) = 0;
};


template < class T >
class cMemberDispatcher : public cDispatcher
{
public:
typedef bool ( T::*tMemberFunc )( int );

cMemberDispatcher ( T *obj, tMemberFunc memFn ) : mInstance ( obj ), mFunction ( memFn ) { };

bool dispatch( int x )
{
return ( mInstance->*mFunction )( x );
}

T *mInstance;
tMemberFunc mFunction;
};



and then this is how you use it:

class cTest
{
public:
bool test ( int x )
{
// whatever code you want...
int y = x;
y++;

return true;
}
};

void TestDispatcher ( )
{
cTest test;
cDispatcher *dispatcher = new cMemberDispatcher<cTest> ( &test, &cTest::test );
bool ret = dispatcher->dispatch ( 10 );

}



I hope thats useful :)

Share this post


Link to post
Share on other sites
Thank you, that is exactly what I wanted to do. Adding a name and id to the dispatcher class and it is ready for use. Not that my scripting engine is anywhere near ready enough to actually be able to execute some c++ code, it was just something I was wondering about. I will keep this thread with my bookmarks so when the time comes I can use the code you posted. Thank you very much.

Share this post


Link to post
Share on other sites
Quote:
Original post by thefries
Don't listen to people telling you what you WANT to use if you don't want to use it.

No one is telling anyone what they "want" to use. They are just pointing out that a well tested library that handles this exists already.
Quote:

I think this community is breeding a generation of game scripters, rather than programmers who understand the low level intricacies of the language they're using.

Well ... this is gamedev.net, not c-plus-plus-innards.net.

Besides, I find that the people who understand the intricacies of a language like C++ are usually the ones who recommend avoiding them where possible. C++ is prone to biting back - hard - when you poke it deeply.
Quote:

You're kinda on the right track with what you're trying to do. This code should give you an idea of how to properly bind a member function. But for full support of multiple arguments/parameters i would recommend you look into how luaPlus does its binding, you can download their callback dispatcher as a package on its own, but its quite template heavy and hard to understand for a beginner (and theres a couple of bugs in it).

Something like boost::bind, except worse?

Share this post


Link to post
Share on other sites
Quote:
Original post by rip-off
No one is telling anyone what they "want" to use.


orly?

Quote:
Original post by nullsquared
That's precisely why you want to use boost.


Quote:
Original post by rip-off
Well ... this is gamedev.net, not c-plus-plus-innards.net.

Besides, I find that the people who understand the intricacies of a language like C++ are usually the ones who recommend avoiding them where possible. C++ is prone to biting back - hard - when you poke it deeply.


If you ever plan on working for a game company and you don't want to be making Java mobile games for the rest of your life, you'd be making a mistake by answering an interview question like "how would you write a simple function binding system" with "use boost::bind"

I'm sorry to break the news to you, but you need to know a little about the language before anyone is going to consider hiring you. They certainly don't want to hire someone thats going to be breaking their codebase constantly because they don't understand it.

And yes, boost::bind is probably more functional than the luaplus callback dispatcher, and probably less buggy, but I'd be a moron to want to include 11 megs of slow to compile headers and a double moron to want to try and decipher the code.

Share this post


Link to post
Share on other sites
Quote:
Original post by thefries
Quote:
Original post by rip-off
No one is telling anyone what they "want" to use.


orly?

Quote:
Original post by nullsquared
That's precisely why you want to use boost.


My apologies - I did skim the thread looking for something phrased like that but didn't see it. Probably should have used the browser search instead =)

Quote:
Quote:
Original post by rip-off
Well ... this is gamedev.net, not c-plus-plus-innards.net.

Besides, I find that the people who understand the intricacies of a language like C++ are usually the ones who recommend avoiding them where possible. C++ is prone to biting back - hard - when you poke it deeply.


If you ever plan on working for a game company and you don't want to be making Java mobile games for the rest of your life, you'd be making a mistake by answering an interview question like "how would you write a simple function binding system" with "use boost::bind"

Maybe. I am quite a competent software developer. I can use libraries and build my own. In an interview I will point out I can do both. I'm sure the company will be glad to hear they don't have to throw out their old code just because "the new kid" wants to reinvent the wheel.
Quote:

I'm sorry to break the news to you, but you need to know a little about the language before anyone is going to consider hiring you. They certainly don't want to hire someone thats going to be breaking their codebase constantly because they don't understand it.

I know plenty about C++. Don't be a fool, use of boost absolutely does not imply that one is ignorant about C++.
Quote:

And yes, boost::bind is probably more functional than the luaplus callback dispatcher, and probably less buggy, but I'd be a moron to want to include 11 megs of slow to compile headers and a double moron to want to try and decipher the code.

Depends. For a small PC game I would take the well tested version. If I have other constraints, I can work under them. Plus, I haven't actually needed to decipher the boost code. Its excellent documentation makes it easy to use. I am flexible, not a "moron", when I use boost.

I could write a replacement. But... why? Unless someone pays me to do it, in which case I don't mind at all [smile]

Share this post


Link to post
Share on other sites
Thats absolutely fine. I also think boost can be a great tool if someone wants to make a small game themselves, but thats where it ends for me.

My comments are based on the point of view that people coming here want to someday work as a professional in the industry, and as such, they will need to know the details on how to implement such things.

If they ask a question about how to implement something, i don't think telling them to use a black box is a good response and as useful as boost can be, i don't find it to be a good learning aid. It's written in a way that makes most professional game programmers cringe. So again, i don't think its a good place to start from when trying to figure out or learn implementation details.

Share this post


Link to post
Share on other sites
I'm not interested in a job in the industry. I like to program small things (including games), but I enjoy the systems behind them the most. I spent most of my time writing little libraries and not games. And I do this just for knowledge and fun. Sure its nice that I get recommended libraries that can do that kind of stuff, but that is not my goal. See it like this, some people like puzzles, but I like this kind of stuff. I rarely use the standard library (and is most likely why I never finish the games I'm trying to create), only the classes that I already made a long time ago and lost the source of. But I'm aware of the fact that other people have other goals when they are programming.

Share this post


Link to post
Share on other sites
Quote:
Original post by thefries
Thats absolutely fine. I also think boost can be a great tool if someone wants to make a small game themselves, but thats where it ends for me.

My comments are based on the point of view that people coming here want to someday work as a professional in the industry, and as such, they will need to know the details on how to implement such things.

If they ask a question about how to implement something, i don't think telling them to use a black box is a good response and as useful as boost can be, i don't find it to be a good learning aid. It's written in a way that makes most professional game programmers cringe. So again, i don't think its a good place to start from when trying to figure out or learn implementation details.
This seems a little black and white to me. There's a number of reasons developers avoid Boost and parts of the SC++L in certain situations, but if I'm not mistaken, these libraries *are* starting to find some use in professional game development (including console titles).

As has been mentioned though, it really depends on what your goals are, and the OP has made it pretty clear that he enjoys writing low-level code for its own sake. Nevertheless, recommending Boost or the SC++L is a perfectly reasonable response to this sort of question.

Share this post


Link to post
Share on other sites
Quote:

I'm sorry to break the news to you, but you need to know a little about the language before anyone is going to consider hiring you.

I'm sorry to break the news to you, but boost::bind is going to be part of the language (std::tr1::bind). I thought you knew a little about the language.

Quote:

And yes, boost::bind is probably more functional than the luaplus callback dispatcher, and probably less buggy, but I'd be a moron to want to include 11 megs of slow to compile headers

You mean 4KB? That's function.hpp and bind.hpp combined.

Quote:
and a double moron to want to try and decipher the code.

That's why you don't have to decipher the code to use it effectively when it comes to the SC++L and boost.

Share this post


Link to post
Share on other sites
Quote:

You mean 4KB? That's function.hpp and bind.hpp combined.


Interestingly my boost/bind.hpp is 58 kB. They also include other headers which in turn probably include other headers.

(Not that one shouldn't use boost, especially if these things make into the SC++L.)

Share this post


Link to post
Share on other sites
Quote:
Original post by nullsquared
I'm sorry to break the news to you, but boost::bind is going to be part of the language (std::tr1::bind). I thought you knew a little about the language.

You mean 4KB? That's function.hpp and bind.hpp combined.

That's why you don't have to decipher the code to use it effectively when it comes to the SC++L and boost.


Lol, you obviously have no idea what you're talking about, and i can't be bothered to spell it all out for you. You've missed my point completely, and are testament to the fact that this community is breeding a generation of scripters.

Share this post


Link to post
Share on other sites
Quote:
Original post by visitor
Quote:

You mean 4KB? That's function.hpp and bind.hpp combined.


Interestingly my boost/bind.hpp is 58 kB. They also include other headers which in turn probably include other headers.


Oh yeah good point [grin]. Still, 58KB is 0.5% of the originally mentioned 11MB [wink].

Quote:
Original post by thefries
Lol, you obviously have no idea what you're talking about, and i can't be bothered to spell it all out for you. You've missed my point completely, and are testament to the fact that this community is breeding a generation of scripters.

Nice generic comeback there buddy. May I suggest you add some actual detail in there before I start to take you seriously?

Share this post


Link to post
Share on other sites
Quote:
Original post by nullsquared
You mean 4KB? That's function.hpp and bind.hpp combined.


When you include function.hpp, that includes iterate.hpp, prologue.hpp, workaround.hpp and functionX.hpp.

iterate.hpp includes dec.hpp, inc.hpp, elem.hpp, size.hpp, cat.hpp, slot.hpp and elem.hpp

prologue.hpp includes functional.hpp, throw_exception.hpp, config.hpp, function_base.hpp, mem_fn.hpp, is_integral.hpp, enum.hpp, enum_params.hpp, cat.hpp, repeat.hpp, inc.hpp and is_void.hpp

I'm going to stop there because i don't have all day, but can you see where this is going? So yes, i think you have no clue of what you're talking about.

Quote:
Original post by nullsquared
I'm sorry to break the news to you, but boost::bind is going to be part of the language (std::tr1::bind). I thought you knew a little about the language.

That's why you don't have to decipher the code to use it effectively when it comes to the SC++L and boost.


Both of these comments indicate that you have missed my point or just haven't bothered to read the thread properly. If you want me to re-iterate...

Quote:
Original post by thefries
Thats absolutely fine. I also think boost can be a great tool if someone wants to make a small game themselves, but thats where it ends for me.

My comments are based on the point of view that people coming here want to someday work as a professional in the industry, and as such, they will need to know the details on how to implement such things.

If they ask a question about how to implement something, i don't think telling them to use a black box is a good response and as useful as boost can be, i don't find it to be a good learning aid. It's written in a way that makes most professional game programmers cringe. So again, i don't think its a good place to start from when trying to figure out or learn implementation details.


My point isn't about what is in the language or not, its how effective YOU as a coder are. If you can use these libraries, good for you buddie. But just because you can use them doesn't mean you have any idea about how they work or how to write them yourself. If you cant write them yourself, then you're not quite good enough as a programmer to be hired by anyone other than a mobile developer, or possibly a junior position at a semi-decent company.

And yes, you do'nt need to decipher the boost code to be able to use it, but again, thats not my point. My point with that comment is that boost isnt a very good place to look if you want to learn how to write such functionality yourself, because its not easy to follow. Not because its too complex for anyone to understand, its because it looks like its the winning entry in an obfuscation contest.

So again, i think you have no clue of what you're talking about. Thanks for making me waste my time.

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.
Sign in to follow this