Question

I am trying to implement a templated ODE solver with the following function declaration:

template<class ODEFunction,class StopCondition=decltype(continue_always<ODEFunction>)> 
bool euler_fwd(ODEFunction& f,typename State<ODEFunction>::type& x_0
    ,double t_0,double dt,size_t N_iter
    ,StopCondition& cond=continue_always<ODEFunction>);

The full source:

/*From SO answer*/

template<class F>
struct State;

template <class R, class... A> 
struct State<R (*)(A...)>
    {
    typedef R type;
    };

/*End from SO answer*/


/**Default stop condition. Always return 0 to continue operation.
*/
template<class ODEFunction>
bool continue_always(const typename State<ODEFunction>::type& x_0,double t_0)
    {return 0;}

/**Euler forward solver
*/
template<class ODEFunction,class StopCondition=decltype(continue_always<ODEFunction>)> 
bool euler_fwd(ODEFunction& f,typename State<ODEFunction>::type& x_0
    ,double t_0,double dt,size_t N_iter
    ,StopCondition& cond=continue_always<ODEFunction>)
    {
    size_t k=0;
    while(N_iter)
        {
        if(cond(x_0,t_0))
           {return 1;}
        x_0+=dt*f(x_0,k*dt);
        --N_iter;
        ++k;
        }
    return 0;
    }

trying to call euler_fwd with a simple function

double f(double x,double t)
    {return x;}

omitting the continue_always predicate, GCC writes

error: invalid use of incomplete type 'struct State' bool continue_always(const typename State::type& x_0,double t_0)

...

test.cpp:18:47: error: no matching function for call to 'euler_fwd(double (&)(double, double), double&, double&, double&, size_t&)'

EDIT:

If I try to skip the use of default argument for cond:

euler_fwd(testfunc,x_0,t_0,dt,N,continue_always<decltype(testfunc)>);

I still get an error

test.cpp:18:97: note: could not resolve address from overloaded function 'continue_always'

Was it helpful?

Solution

Instead of trying to manipulate the function types (types of f, cond), why not make the state a template argument?

#include <cstdlib> // for size_t
#include <functional>

template<class R>
bool continue_always(const R& x_0,double t_0)
{return 0;}

template<class R> 
bool euler_fwd(std::function<R(const R &)> f,R& x_0
  ,double t_0,double dt,size_t N_iter
  ,std::function<bool(const R&, double)> cond=continue_always<R>)
{
  size_t k=0;
  while(N_iter)
  {
    if(cond(x_0,t_0))
      {return 1;}
    x_0+=dt*f(x_0,k*dt);
    --N_iter;
    ++k;
  }
  return 0;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top