Search code examples
c++odeint

function call missing argument list


I'm trying to use odeint (i.e. library for solving differential equations) inside a class but I couldn't. I really need to put it inside a class so that I can have control over my project. This is the error I'm getting error C3867: 'robot::sys': function call missing argument list; use '&robot::sys' to create a pointer to member

and this is my code

#include <iostream>
#include <boost/numeric/odeint.hpp>

using namespace std;
using namespace boost::numeric::odeint;

/* The type of container used to hold the state vector */
typedef std::vector< double > state_type;

class robot
{
    double g, dt, t;
    runge_kutta_dopri5<state_type> stepper;

public:
    state_type x;

    robot() : x(2)
    {
        x[0] = 1.0;
        x[1] = 0.0;
        t = 0;
        g = 0.15;
        dt = 0.1;
    }

    void move();
    void sys(const state_type &x, state_type &dx,  double t);
};


void robot::move()
{
    stepper.do_step(sys , x , t, dt );
    t += dt;
}


void robot::sys( const state_type &x , state_type &dx ,  double t )
{
    dx[0] =  x[1];
    dx[1] = -x[0] - g*x[1];
}



int main(int argc, char **argv)
{
   robot Robo;

   for ( size_t i(0); i < 100; ++i){
       Robo.move();
   }


    return 0;
}

When I try the solution that is suggested in the error message, I'm getting another error which is

....\odeint\stepper\base\explicit_error_stepper_fsal_base.hpp(279): error C2064: term does not evaluate to a function taking 3 arguments


Solution

  • sys is a non-static member function; they do not behave like normal functions because they have an implicit this parameter.

    Possible fixes are:

    (1) Use a C++11 lambda in place of sys:

    void robot::move()
    {
        stepper.do_step([this](const state_type &x, state_type &dx, double t){
            dx[0] =  x[1];
            dx[1] = -x[0] - g*x[1];
        }, x , t, dt );
        t += dt;
    }
    

    (2) Keep sys and use std::bind or boost::bind:

    void robot::move()
    {
        using namespace std::placeholders;
        stepper.do_step(std::bind(&robot::sys, this, _1, _2, _3), x , t, dt );
        t += dt;
    }
    

    (3) Use a custom-written functor instead of sys:

    struct System {
        double g;
        explicit System(double g) : g(g) {}
        void operator()( const state_type &x , state_type &dx ,  double t )
        {
            dx[0] =  x[1];
            dx[1] = -x[0] - g*x[1];
        }
    };
    
    void robot::move()
    {
        stepper.do_step(System(g), x , t, dt );
        t += dt;
    }
    

    Note that in this case you can have your class store a System object instead of storing g and constructing it on each call to move.