function pointers... [SOLVED]

Started by
20 comments, last by the_moo 17 years, 11 months ago
ok, i'm now trying to use boost::function and am only having one problem with it. when i try to compile the only error messages i get are like this:

In static member function `static R boost::detail::function::function_obj_invoker2<FunctionObj, R, T0, T1>::invoke(boost::detail::function::any_pointer, T0, T1) [with FunctionObj = boost::_mfi::mf4<void, MeshInstance, float, float, float, bool>, R = int, T0 = ObjectX*, T1 = std::list<void*, std::allocator<void*> >]':

479 D:\Program Files\Dev-Cpp\Other Libs\Boost\include\boost-1_33_1\boost\function\function_template.hpp
instantiated from `void boost::function2<R, T0, T1, Allocator>::assign_to(FunctionObj, boost::detail::function::function_obj_tag) [with FunctionObj = boost::_mfi::mf4<void, MeshInstance, float, float, float, bool>, R = int, T0 = ObjectX*, T1 = std::list<void*, std::allocator<void*> >, Allocator = std::allocator<void>]'

and there's about 10 of them all with slight variances to the error but all "instantiated from 'boost::function2'".

The line which causes these errors to show is:
QueueAction(&MeshInstance::Move,args);

the prototype for this function is:
typedef boost::function<int (class ObjectX* classtype, list<void*> args)> QueueFunc;
void QueueAction (QueueFunc func, list<void*> args);

basically MeshInstance::Move is the function that i'm trying to create a pointer to.

i have never seen this type of error before but i'm assuming it has something to do with templates.

if anyone has any idea and can help me... again... i'd be very grateful

thanks,
the_moo
Advertisement
It looks like you're missing part of the error message. After those, there's generally a message about what is actually wrong.

Anyways, this works for me [gcc 3.3.5]:
#include <boost/function.hpp>#include <iostream>#include <list>using namespace std;class X{};class MeshInstance{public:static int Move(X *objx, list<void *> args){    cout << "In Move\n";}};struct Command{    boost::function<int(X *,list<void *>)>   fobj;};int main(){    Command        cmdobj;    X              *xobj=new X();    list<void *>   voidlist;    cmdobj.fobj=&MeshInstance::Move;    cmdobj.fobj(xobj,voidlist);}


the first thing I'd check is that MeshInstance::Move actually returns an int, and not void.

And once you have it working, you might want to think about changing your design so that list<void *> is no longer necissary.

[Edited by - Telastyn on May 3, 2006 11:24:01 PM]
An alternative (and potentially much cleaner) solution to this is to employ the Command pattern. The way it works is fairly simple:

  • Define a Parameter type. The simplest type you might want to use (that is still flexible) might be boost::variant. You can also use a std::pair<std::string, boost::variant> to implement named parameters - which personally I'd highly recommend. (Another solution to named parameters is to use the name as an index in a hashmap.)

  • Define an abstract base class Command that has a pure virtual function Execute and exposes a set of Parameters.

  • Define a concrete subclass for each individual command you want to support, e.g. MakeThingExplodeCommand. Override Execute in each subclass to look at the parameter set and act accordingly.

  • You can now queue references to Command objects and Execute them safely without knowing any details about them, thanks to polymorphism.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

You should post the rest of one of the error messages, and also the code where you are actually getting the error.
Quote:Original post by ApochPiQ
An alternative (and potentially much cleaner) solution to this is to employ the Command pattern. The way it works is fairly simple:

  • Define a Parameter type. The simplest type you might want to use (that is still flexible) might be boost::variant. You can also use a std::pair<std::string, boost::variant> to implement named parameters - which personally I'd highly recommend. (Another solution to named parameters is to use the name as an index in a hashmap.)

  • Define an abstract base class Command that has a pure virtual function Execute and exposes a set of Parameters.

  • Define a concrete subclass for each individual command you want to support, e.g. MakeThingExplodeCommand. Override Execute in each subclass to look at the parameter set and act accordingly.

  • You can now queue references to Command objects and Execute them safely without knowing any details about them, thanks to polymorphism.


Quoted for emphasis.

There is also boost::any in addition to boost::variant. I don't really know the differences and pros/cons, but it's probably worth looking at both.

Quote:Original post by Zahlman
There is also boost::any in addition to boost::variant. I don't really know the differences and pros/cons, but it's probably worth looking at both.


The difference between the two is:


  • boost::any can be an infinite number of types but only one type at any given time, boost::variant can only be a finite set of types and as with boost::any only one type at any given time.


  • boost::any types do not need to be known up front while for boost::variant they do.


  • boost::any uses a technique called automatic type erasor, basically internally boost::any at the very last moment erases static type information into a base type. For primitive operations such as copying delegates to virtual member functions of the base type for other operations clients have to use type switching and/or casting.


  • boost::variant internally uses unions and metaprogramming to keep the static type information, type dispatch/resolution can be done at compile-time aswell as run-time.


  • boost::variant is more type safe than boost::any



So boost::variant is more efficent while boost::any has more flexiablity when it comes to unknowns. Both can represent the samethings such as recusive types/data structures like cons lists or trees but with boost::variant you get sort of pattern matching using static visitors with boost::any you have to resort to runtime type queries. So i would make boost::variant the default choice unless you do not know what and/or the number of types you will be dealing with in advance.
Telastyn, ApochPiQ, jpetrie, Zahlman and snk_kid: thank you all so much! all of you have given great advice (and so much of it [smile]). as soon as i get the chance i'm going to put all the information together and use it to come up with my preferred method for attacking this [grin]!

thanks a heap once again! i'll be sure to ask again if there's anything i'm still struggling with (especially with boost:: ... i've never used before now so it's all a bit dawnting(??)!!)

thanks once more,
the_moo
hey again,
ok i've got the game compiling now but i think there is a problem with one of my casts (which to be honest i don't like doing but i can't see any other way...).

for some reason i can't post large code chunks... so my next post has all the code that i would've had here; please take a look at it now if you're trying to help me out because the rest of this post will make sense then. thanks [smile]

ok i know that's a lot of code but i want to get this now that i feel i'm so close!
firstly i'm pretty sure the problem stems from the QUEUEITEM.customfunc member and i think that problem is caused by boost::any being the function pointer paramter...
**1: ObjectX is the base class i derive all my mesh and sprite based entities from (and those get derived from too). i've left out most variables but the one concerning this problem to make things clearer.
**2: i've made ExecuteAction pure virtual because when calling queued functions i need to have a pointer to the instance of the class that is actually calling it (so this works fine) so that any function being called will be found (so if i have a pointer to an ObjectX instance it will call the highest order ExecuteAction and all member functions will still be found).
**3: MeshInstance::QueueAction is the problem at the moment. the implementation of it is shown and line **4 shows the exact line:
**4: this is the line that is causing my game not to crash as such, but just quit out rather quickly with no error message. if i remove this line, everything works fine (i've yet to place ExecuteAction into my game so it is never called - no point till QueueAction works). now i've tried casting "func" as well but that caused more compile time errors like before.

i guess i'm asking: is there any way i can have a "customfunc" variable type that supports casting to the correct function pointer type when calling and assigning the function?
again i realise this is quite a bit to ask but it's the ideal way that i can visualize to solve this problem.

thanks a heap in advance,

[Edited by - the_moo on May 8, 2006 3:52:48 AM]
the_moo
typedef boost::function<void (boost::any classtype, list<void*> args)> QueueFunc;

typedef struct QUEUEITEM {
QueueFunc customfunc;
list<void*> args;
};

class ObjectX { //**1
friend class DirectX;
protected:
list<QUEUEITEM> action_list;

public:

ObjectX ();
void ClearQueue ();
virtual void ExecuteAction () = 0; //**2
};

class MeshInstance : public ObjectX {
public:
MeshInstance ();
void SetBaseMesh (MeshX *basem, std::string meshname);
MeshX* GetBaseMesh ();
void Move (float x, float y, float z, bool world = false);
void QMove (list<void*> args);
void SetPosition (float x, float y, float z);
void SetColour (int alpha, int red, int green, int blue);
void SetScale (float width, float height, float depth, bool inc = false);
void SetAnimation (std::string animname);
void UnsetAnimation ();
void Rotate (float angx, float angy, float angz);
void RenderPass (LPDIRECT3DDEVICE9 pd3ddev, int pass);
void Render (LPDIRECT3DDEVICE9 pd3ddev);
void QueueAction (boost::function<void (MeshInstance* ptr, list<void*> args)> func, list<void*> args); //**3
virtual void ExecuteAction ();
bool Release ();
};

void MeshInstance::QueueAction(boost::function<void (MeshInstance* ptr,
list<void*> args)> func, list<void*> args)
{
QUEUEITEM item;

item.args = args;
boost::any_cast<boost::function<void (MeshInstance* ptr, list<void*> args)> >
(&item.customfunc) = func; //**4

action_list.push_back(item);
}

void MeshInstance::ExecuteAction()
{
boost::function<void (MeshInstance* ptr, std::list<void*> args)> funcptr;
funcptr = boost::any_cast<boost::function<void (MeshInstance* ptr,
std::list<void*> args)> >(action_list.front().customfunc);
funcptr(this,action_list.front().args);
action_list.pop_front();
}
the_moo
Quote:Original post by the_moo
**4: this is the line that is causing my game not to crash as such, but just quit out rather quickly with no error message.


Read as: Crash without diagnostic message.
Best guess as to cause: it's throwing a boost::bad_any_cast.

Then again my brain is having major problems grokking that code. Please use [ source ] tags in the future...

EDIT: There we go, brain parser click.

The any_cast isn't doing what you're expecting.

Each boost::function< ... > is a full blown type.

So when you do:

boost::any_cast<boost::function<void (MeshInstance* ptr, list<void*> args)> >(&item.customfunc) = func; //**4


You're converting:
boost::function<void (boost::any classtype, list<void*> args)> *    (a pointer to a boost::function<>)=> boost::any=> boost::function<void (MeshInstance* ptr, list<void*> args)>   (by-value boost::function<> of different type)


Which isn't valid.

That entire line is messed up, as is the definition of func. You're going to need to write a translation function or change func's definition, and thus how you'd write func. For best results, you'd probably be putting the any_cast inside of the function that you want to pass... e.g.:
void ExampleFunc( boost::any first , list< void * > args ) {     MeshInstance * mesh = boost::any_cast< MeshInstance * >( first );     ...}

Then, you can call:

QueueAction( & ExampleFunc , ... );

Where QueueAction has:

QueueFunc func,

as that argument's type.

[Edited by - MaulingMonkey on May 8, 2006 10:51:35 AM]

This topic is closed to new replies.

Advertisement