Skip to main content
gamedev.net
🔒 Locked

Functor question

Started by daniel_i_l 5 replies 1.4k views
Original Post
daniel_i_l
daniel_i_l
Let's say that I have a class Simulation that contains a pointer to an integrator of type Integrator. The integrator class has a function "integrate" which takes a state and a function that can calculate the derivative of the state and returns the new state. The obvious way to implement this is with function pointers like this:

class Simulation
{
...
    Integrator *integrator;
    float[] GetDerivatives(float[] state, float dt);
    void Update(float dt);
};
void Simulation :: Update(float dt)
{
    integrator.integrate(..., &GetDerivatives);
}
class Integrator
{
...
    float[] integrate(float[] state, float t0, float t1, 
                      float[] (*GetDxDt)(float[] state, float dt));
};



But is there any more "c++" way of doing it such as functors? The problem is that the GetDerivatives function has to use other functions and information that're contained in "Simulation" (bodies,forces...). So if I made a "GetDerivatives" functor it'd have to hold a pointer to Simulation - and in that case I could just give "Integrator" a pointer to "Simulation" and let it use the function directly. It just seems like bad design to have objects point to each other. Are there better ways of implementing this? Thanks.
"We've all heard that a million monkeys banging on a million typewriters will eventually reproduce the entire works of Shakespeare. Now, thanks to the internet, we know this is not true." -- Professor Robert Silensky
powell0
powell0
I don't know if this is the best way to do it, but you could use boost::function to define a function object that supports the GetDerivatives function signature and then use boost::bind to bind the GetDerivatives member function to the function object.

So your code would look something like:

// Create a typedef of the function objecttypedef boost::function<float[](float[] state, float dt)> derivativeFunction;class Simulation{...    Integrator *integrator;    float[] GetDerivatives(float[] state, float dt);    void Update(float dt);};void Simulation :: Update(float dt){    // create the function object and bind it to the GetDerivatives member function    derivativeFunction derivFunction = boost::bind(&Simulation::GetDerivatives, this, _1, _2 );    integrator.integrate(..., derivFunction);}class Integrator{...    float[] integrate(float[] state, float t0, float t1, derivativeFunction derivFunction);};float[] Integrator::integrate(float[] state, float t0, float t1, derivativeFunction derivFunction){...float[] newState;// Call the function objectstate = derivFunction(...);}


I think that would work. I've only used boost::function and boost::bind a little bit.
alvaro
alvaro
I am not sure I understand all the issues involved in your situation, but this sounds to me like a place for the "curiously recursive template pattern":
template <class SIM>class Integrator {  // ...public:  void integrate(...) {    // ...    derivatives = get_derivatives(...);    // ...  }};class Simulation : public Integrator<Simulation> {  float [] get_derivatives(...);  // ...};


If that's not clear enough (it can be confusing at first), I can try to write a complete example for a trivial case.

EDIT: I don't even think I got it right in the very incomplete code above. I'll post something when I have it working. Unfortunately, I have to go to work now.
loufoque
loufoque
What language is that supposed to be?
Because this is definately not C++. "float[] state" is not a valid declaration.

Also, I don't understand why boost::function was recommended. You don't need type erasure here, you can just use functors directly using templates.
alvaro
alvaro
loufoque is right. You just need to use a regular functor. This is an example of how to define the integrator:

#include <iostream>template <class Time, class Point, class Vector, class DerivativeFunction>class EulerIntegrator {  DerivativeFunction derivative;public:  EulerIntegrator(DerivativeFunction const &derivative) : derivative(derivative) {  }    // I am trying to be clear, not to avoid making copies.  // Perhaps there is room for optimizations here.  Point step(Point const &position, Time dt) {    Vector velocity = derivative(position);    Point result = position + dt * velocity;    return result;  }};class Proportional {  float scale;public:  Proportional(float scale) : scale(scale) {  }  float operator()(float x) {    return scale*x;  }};int main() {  Proportional identity(1.0f);  EulerIntegrator<float, float, float, Proportional> integrator(identity);  float x=1.0f;  for(int i=0;i<10;++i) {    x = integrator.step(x, 0.1f);    std::cout << x << '\n';  }}
daniel_i_l
daniel_i_l
Thanks for the help. I have one question though.
In my case the "DerivativeFunction" needs to use information from "Simulation" such as forces. So would the functor need to hold a pointer to "Simulation"? Is there a way to design it so that it won't have to?
Thanks.
"We've all heard that a million monkeys banging on a million typewriters will eventually reproduce the entire works of Shakespeare. Now, thanks to the internet, we know this is not true." -- Professor Robert Silensky
CRACK123
CRACK123
Why not keep it simple and pass the class along using the this pointer.

float[] GetDerivatives(Simulation *sim, float[] state, float dt);

and then do

functionPointer(this, state, dt));
The more applications I write, more I find out how less I know

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.