Archived

This topic is now archived and is closed to further replies.

Kafeen

Function pointer fun

Recommended Posts

Kafeen    122
I''m having a slight problem with a few function pointers that someone might be able to help me with. First I have a list of function pointers. std::list functionList; Then I have a function to add them (basicly just calls push_back but it means I can keep the list private) void AddObject(void (*func)() ); Then I have my classes class Object { public: void Render(); }; I want to do something along the lines of : AddObject(obj.Render); to add them onto my list of render functions to keep the requests to render objects and the actual calls to the functions seperate but I keep getting : cannot convert parameter 1 from ''void (void)'' to ''void (__cdecl *)(void)'' I''m probably missing something obvious but everything I try doesn''t quite work. Any suggestions?

Share this post


Link to post
Share on other sites
Oxyd    1157
Well - Object::Render () is in fact Object::Render (Object *this). But the compiler hides the first parameter from you. You know the 'this' pointer - this is how it works. However, I think, that if you declare the prototype for list as std::list <void (*func)(Object *)> it won't work either. Try to use static member function, if that's possible.

Oxyd

---
- Unreadable code is code written on a piece of paper, but not the one, in which the programmer is using a space in the place you don't.
- Real programmers aren't afraid of goto

[edited by - Oxyd on March 27, 2004 2:30:59 PM]

[edited by - Oxyd on March 27, 2004 2:31:38 PM]

Share this post


Link to post
Share on other sites
Kafeen    122
Problem then is that I can't use non-static members of it from the function.

[edited by - Kafeen on March 27, 2004 2:55:30 PM]

Share this post


Link to post
Share on other sites
Queasy    157
i think the trick is to have the static method take in, as parameter, a pointer to the class.

class C {
public:
static void static_hi(C*) {
c->hi();
}

void hi() {
printf("sup\n");
}
};

void blah(void (*f)(C*),C* c) {
f(c);
}

main() {
C* blah=new C();
blah(C::static_hi,c);
}




HOWEVER: i have been able to send pointers to methods as parameters.. but i haven''t had much luck in actually calling the method. Maybe you will have more insight with this:

void blah(void (C::*m)()) {
}

main() {
blah(&C::hi);
}

according to some gcc error messages, "&C::method" is considered a pointer to method.

very strange.

-j

Share this post


Link to post
Share on other sites
jdhardy    469
If all else fails, get a bigger hammer: boost.bind. It's intimidating at first, but it works like a charm. Combined with boost.function, you don't even need raw function pointers.


#include <boost/bind.hpp>

typedef boost::function<void ()> func_t;

std::list<func_t> functionList;

void AddObject(func_t func)
{
functionList.push_back(func);
}

class Object
{
public:
void Render();
};

int main()
{
Object obj;

AddObject(boost::bind(&Object::Render, boost::ref(obj)));
}
Off the top of my head, so it could be wrong.

Basically, boost.bind creates a function object, which is a class that behaves like a function, and attaches (or "binds") arguments to it. These arguments will stay with the function object at all times. In this case, boost::ref is used to create a reference to the object instead of a copy.

[edited by - ze_jackal on March 27, 2004 3:57:07 PM]

Share this post


Link to post
Share on other sites
Desert Fox    277
The problem is that simple function pointers and member functions pointers have different calling syntax. To call a member function pointer, it's of the form obj.*FunPtr(Interestingly enough, the value returned by the .* operator has no type, and is thus not storable). Basically, you need to use some type of functor to do what you want (or some crude hack involving static members, etc.). I suggest looking up Loki::Functor for a good generalized functor. I don't have time to go through a proper implementation of the type of functor you need, but if you have any questions about Loki's functor I can probably answer them.


General usage of Loki::Functor


#include "Typelist.h"
#include "Functor.h"

typedef Loki::Functor<void,Loki::NullType> FunctType;

std::list<FunctType> functionList;

void AddObject(FunctType fun)
{
functionList.push_back(fun);
}

void MyFunc () {}
class Object
{
public:
void Render() {}
};

int main()
{
Object p;
AddObject(FunctType(MyFunc));
AddObject(FunctType(&p,Object::Render));

return 0;
}


I suggest Loki::Functor over boost::bind, I find it cleaner in general.


[edited by - desert fox on March 27, 2004 4:10:32 PM]

Share this post


Link to post
Share on other sites
Thrump    169
Could you store an array of your objects then go through the list calling the render method on each one? This won''t work if you want more than 1 render function for any concrete object though.

for(each object)
obj->Render();

for_each(objectList.begin(), objectList.end(), Object::Render);

If this isn''t what you want, www.function-pointer.org is an excellent reference. It will show you how to make a pointer to a member function.

Share this post


Link to post
Share on other sites
Queasy    157
hey.. i got it.


//btw, how do you guys post code on here?

#include <stdio.h>

class BARGLE {
public:
int i;
BARGLE() {}
void print() {
printf ("hi %d\n",i);
}
};


typedef void (BARGLE::*BARGLEMETHOD) ();

class MYCLASS {
public:
MYCLASS() {}

void doIt(BARGLEMETHOD methodPtr , BARGLE *instance)
{
(instance->*methodPtr)();
}
};

int main () {
BARGLE b,b2;
b.i=123;
b2.i=456;
MYCLASS c;
c.doIt((BARGLEMETHOD)&BARGLE:rint,&b);
c.doIt((BARGLEMETHOD)&BARGLE:rint,&b2);
return 0;
}


the method "doIt" is of interest. First parameter is method pointer. Second parameter is instance.

I see that this is tied to a specific class-type but I bet you can get around this with templates.

Hope this helps!

-j

Share this post


Link to post
Share on other sites
Kafeen    122
Thanks for the help but I''ve thought of a better way to do things without needing to access a member function through a pointer.

I couldn''t have done it that way Queasy because I wanted to be able to access the render functions of more than one type of class which is why I was trying to store a pointer to the render function and not just a pointer to the object I wanted to render with its own meber function.

Share this post


Link to post
Share on other sites
jdhardy    469
Queasy: [ source ] [ /source ] or [ code ] [ /code ] (without the spaces). source gives you the boxes; code keeps it inline but uses fixed-width fonts.

Share this post


Link to post
Share on other sites
Queasy    157
oh.. i had thoguht you would have derived each of those classes from some base class.. eg. "class RENDERABLE" which will have the render method. Then you can cast down to base class.

ps: thanks jackal for the tag-tips.

-j

Share this post


Link to post
Share on other sites