• 14
• 12
• 9
• 10
• 9

Passing variable argument types

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

Recommended Posts

I have a active object that includes all the 'rendering' for my game. When I want to 'do something' graphical, I write a little function, then send a callback request to this graphics active object. All callback requests sent to the active object go into a little queue, and are processed fifo style, on the active objects own thread. The problem is, how can you store all these functors/callbacks in the queue? I mean, it works great when were just calling nullary functions (they can all fit in one list), but what about a callback that needs some kind of argument (of X type)? So, my question is, how can I pass arguments (of all diferent types) to this active object, have the arguments buffered somewhere, then passed along to the function? Thanks for any insight *keep in mind performance is a huge concern. I did find a solution using boost bind, but it was far to slow to bind every callback request at runtime.

Share on other sites
No ideas?

Best I could think of would be to leave the callbacks all as nullary functions (no arguments). Now they all fit in the 'queue list', and can be processed first in first out. To pass arguments to these functions/callbacks, you could write a special 'argument transporter' function for each argument type (just a simple buffer to store floats, ints, ect.. then read them back fifo once the callback is called).

So something like this...

Quote:
 graphics->callback( &someFunction );graphics->passArgument( someArgument );graphics->passArgument( anotherArgument );...void someFunction( void ) {float arg1 = graphics->getNextFloatArgument();int arg2 = graphics->getNextIntArgument();//do stuff with the two arguments}

Not the most elegant solution, but it 'works'. If you have a better idea im dien to hear it :0

Share on other sites
This sounds like the Command Pattern to me. Instead of passing a callback function, pass a functor (a function object).

There are many more advanced (and correct) ways to do this, but this class sketch should give you the idea. boost::function is one library that can help out, but I understand that it has performance issues.

class IRenderCommand{public:     void Execute() { ExecuteInternal(); };private:     virtual void ExecuteInternal()=0;};class ConcreteRenderCommand:   public IRenderCommand{public:      Matrix transform;      Image  texture;private:      void ExecuteInternal()       {              //Guts of the operation here      }};

Share on other sites
Quote:
 *keep in mind performance is a huge concern. I did find a solution using boost bind, but it was far to slow to bind every callback request at runtime.

This is probably as fast as it gets ( see the referenced article as well). This approach eliminates the penalty of boost's functions and memory allocations it performs.

Share on other sites
There are two problems with boost::function and boost::bind.

For one, how can I maintain a list/queue of boost::functions if they are all different (ie you cant put a nullary function and a function that takes a int argument in the same list).

And two, binding the function at runtime is INSANELY slow. For example, if you wanted to update the position of the camera every frame, its 100x faster to use my method (using a 'preset' binding/callback, and just passing the argument seperately). So I need to setup all my functors/callbacks in the init step, then never touch them again.

Share on other sites
Yes, dynamic binding and other dynamic approaches are "slow". If they are performance issue, you're almost certainly abusing them.

If you're calling these dynamic functions from inside the render loop, that's almost certainly an incredible performance hit that nothing will solve.

Other option is of course virtual functions, and defining callbacks as interfaces. That'll be as fast as it gets for such generic approach.

Share on other sites
Hmm that article on delegates looks interesting (never heard of em before). It looks like just a 'faster' way to use boost::function? I dont see how it solves the problems I listed above though (I missed something I guess?).

@Antheus

The problem is, I dont want to have to hard code a complex interface in my graphics active object. I want to 'hook on' generic callbacks, and pass arbitrary argument types. There has to be a elegant AND performance friendly way...

Share on other sites
Whoops, I guess I skimmed past the bits where you mentioned considering functors already. Now that I look at it, I'm not sure If I can help you with a simple fast and elegant solution to this one.

If you can modify the called function signatures, you could make it a little less ugly by creating a RenderArgs class that handles the "GetIntArg" "GetFloatArg" stuff in your earlier solution to not clutter up the graphics class with that functionality and pass a render args with your function pointer (and recieve it in the function signature).

And Getting into Conjecture of Ideas outside my realm of immediate experience:

If you use bind (or an equivalent) and you fill in concrete arguments, doesn't it return a nullary functor, that you can call later? If these have the same type (and I think they do) you could store lists of them. That would solve half the problem, wouldn't it?

A quick test in my compiler reveals this to be legal:

void CBoostBindTest::Test(){boost::function<void ()> f1 = boost::bind(&CBoostBindTest::Test2, this, 1);}void CBoostBindTest::Test2(int iTest){}

So you could just make sure that you call all of your arguments concretely when you bind.

Or is this the solution you already arrived at using bind?

Share on other sites
Well, you CAN do the following...

Quote:
 std::vector< boost::function > callbackQue;callbackQue.push_back( boost::bind( &someFunction, someFloat, someInt ) );

The problem is, hard binding the arguments like that is INSANELY slow for some reason. Its MUCH faster to just bind a nullary function during app init, and pass the arguments via some other method.

What exactly did you mean by using a "RenderArgs" class? You mean something like boost::any? Wouldnt that cause performance issues?

Share on other sites
Do you mean setup all my callback functions like...

Quote:
 void someFunction( ArgList args ) {//extract arguments form 'args'};

Im not sure how to write a container class like that (one that can take varying argument types)