blooop
blooop

Reputation: 409

How to pass a function pointer to a function from within that function

I'm attempting to create a simple finite state machine in c++. The basic idea is that each state in the FSM does some calculations and then returns a function pointer to the next state. If the state should remain the same then the function returns a pointer to itself. After failing to create get it to work in c++ as desired I implemented it in python as a sanity check.

class FSM:

def __init__(self):
    self.variable =0
    self.currentState = self.state1;            

def state1(self):
    self.variable = self.variable+1;
    print "in state 1, variable =", self.variable
    if self.variable >2:
        return self.state2   
    return self.state1

def state2(self):
    self.variable = self.variable-2
    print "in state2, variable =",self.variable
    return self.state1

def update(self):
    self.currentState = self.currentState()


fsm = FSM();
for i in range(1,10):
   fsm.update()    

This is what I've written in c++, but it does not compile

typedef std::function<void()> fsmFunc;

class FSM
{
  int variable;

  FSM();

  function<fsmFunc()> currentState;

  fsmFunc state1();
  fsmFunc state2();    

  void update();
};

FSM::FSM()
{
  variable =0;
  d.consolePopup<>("sdfsd");
  currentState = bind ( &FSM::state1,this );
}

fsmFunc FSM::state1()
{
  variable++;
  std::cout<<  "In state1, variable: " << variable <<std::endl;
  if ( variable >2 )
     return std::bind ( &FSM::state2,this );
  else
     return std::bind ( &FSM::state1,this );
}

fsmFunc FSM::state2()
{
  std::cout<<  "In state2, variable: " << variable <<std::endl;
  variable-=2;
  return std::bind ( &FSM::state1,this );
}

void FSM::update()
{
  currentState = currentState();
}

I get this error:

note: candidate function not viable: no known conversion from 'function<void ()>' to 'const function<std::function<void ()> ()>' for 1st argument

I have tried lots of different variations but can't get the types to work correctly for the currentState = currentState();

Is this possible in c++?

Upvotes: 0

Views: 107

Answers (2)

Derrick Turk
Derrick Turk

Reputation: 4336

The most direct translation is to construct a recursive type, using what's often called "Fix" or "Mu". I cribbed a bit of my mu definition from http://ericniebler.com/2013/07/16/f-algebras-and-c/.

#include <functional>
#include <iostream>

template<template<class> class T> struct mu;
template<template<class> class T> struct mu: T<mu<T>> {
    explicit mu(T<mu<T>> t) : T<mu<T>>(t) { }
};

template <class Ret> using no_args_fn = std::function<Ret()>;
typedef mu<no_args_fn> fsmFunc;

class FSM
{

    public:
      FSM();
      void update();

    private:
      fsmFunc currentState;

      fsmFunc state1();
      fsmFunc state2();    

      int variable;
};

FSM::FSM()
  : currentState(std::bind(&FSM::state1, this))
{
  variable = 0;
}

fsmFunc FSM::state1()
{
  variable++;
  std::cout<<  "In state1, variable: " << variable <<std::endl;
  if ( variable >2 )
     return fsmFunc(std::bind(&FSM::state2, this));
  else
     return fsmFunc(std::bind (&FSM::state1, this));
}

fsmFunc FSM::state2()
{
  std::cout<<  "In state2, variable: " << variable <<std::endl;
  variable-=2;
  return fsmFunc(std::bind(&FSM::state1, this));
}

void FSM::update()
{
  currentState = currentState();
}

int main()
{
    FSM fsm;
    fsm.update();
    fsm.update();
    fsm.update();
    fsm.update();
}

Upvotes: 1

Jarod42
Jarod42

Reputation: 217275

If you assign next step directly in the method, if would be simpler. Your current way requires some recursive definition type.

class FSM
{
    int variable = 0;
    void (FSM::*currentState) () = &FSM::state1;
public:
    FSM() = default;

    void state1()
    {
      variable++;
      std::cout<<  "In state1, variable: " << variable <<std::endl;
      if ( variable >2 )
         currentState = &FSM::state2;
      else
         currentState = &FSM::state1;
    }

    void state2()
    {
        std::cout<<  "In state2, variable: " << variable <<std::endl;
        variable-=2;
        currentState = &FSM::state1;
    }

    void update() { (this->*currentState)(); }
};

Demo.

Upvotes: 1

Related Questions