6

I've implemented a very minimal finite state machine in a class, and my original approach was to try this:

class Widget {
public:
  void update(float time_interval){
    current_state = current_state_(time_interval);
  }
private:
  std::function<  ??  > off_(float);
  std::function<  ??  > standby_(float);
  std::function<  ??  > locked_(float);

  std::function<  ??  > current_state_; // initialised to off_
};

Each state is a function which returns a state. But I can't work out how to declare a function whose return type includes its return type. Is there a way to break the recursion?

Instead, I used an enum class and an ugly switch statement.

3

2 Answers 2

6

If I understand correctly, you want to return a function reference to the next function in the state chain, and that all the state step functions have identical signature?

I see the problem here is that the return type is the function itself, so declaring the type of the function invokes a recursive type definition.

So you want to write functions of the form RetType fn_(float) but the type of RetType is (basically) RetType fn_(float). So now we have (RetType (*)(float)) fn_(float) or something like that, but however hard we try we can't get rid of RetType.

You can't shut down that recursion without forward declaring something. We can forward declare classes, and use them, so let's write a simple class wrapper for your function pointer, which is perhaps what @Jarod was alluding to. Now, std::function is sort-of a class wrapper for your function, but it needs the explicit type declaration, which we don't have.

class Widget;
class StateFn;
class StateFn
{
  Widget * THIS;
  StateFn (Widget::*Fn)(float);
public:
  /// Or you could rely on POD construction
  StateFn(Widget * THIS, StateFn (Widget::*Fn)(float))
  : THIS(THIS), Fn(Fn)
  {}
  StateFn operator()(float f)
  {
    return THIS->*fn(f);
  }
};

So now the recursive definition is broken, our state functions can return StateFn objects, and we can call on them.

0
0

I've found a solution - using std::unordered_map to substitute the ugly switch:

class Widget {
public:
  enum class State { Off, Standby, Locked };

  void update(float time_interval) {
    current_state_ = (this->*state_fn_.at(state_))(time_interval);
  }

private:
  State off_(float) {return ::has_power() ? State::Standby : State::Off;}
  State standby_(float);
  State locked_(float);

  const std::unordered_map<State, State(Widget::*)(float)> state_fn_{
      {State::Off,     &Widget::off_},
      {State::Standby, &Widget::standby_},
      {State::Locked,  &Widget::locked_}};

  State current_state_{State::Off};
};

It's only 1+3n lines of code worse than the ideal code I put in the question - I'm pretty happy with this!

3
  • Fair enough, but you might as well go for the traditional case statement if you are going to introduce a state enumeration.
    – Gem Taylor
    Commented Apr 3, 2018 at 9:57
  • You could also consider a new derived virtual method-only class for each state.
    – Gem Taylor
    Commented Apr 3, 2018 at 9:59
  • I'm assuming your state enumeration is not just 3 states, so that will have to become multiline as well.
    – Gem Taylor
    Commented Apr 3, 2018 at 10:01

Not the answer you're looking for? Browse other questions tagged or ask your own question.