Reputation: 409
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
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
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