Увеличить диаграмму состояний: возврат в предыдущее состояние

У меня есть конечный автомат, в котором, если я вхожу в определенное состояние, иногда мне требуется регулярный переход в другое состояние, а иногда мне нужно вернуться в предыдущее состояние.

Например, имея состояния A B C, скажем, что переход S перемещает состояние A в C и из B в C. Мне нужно, чтобы переход T перемещал C в A, когда S произошел в состоянии A, и C в B, когда он произошел в состоянии B.

В приведенном ниже коде переход S происходит в состоянии B, и поэтому я хотел бы, чтобы переход T вернулся в состояние B (тогда как в настоящее время он возвращается в состояние A).

#include <boost/mpl/list.hpp>

#include <boost/statechart/state_machine.hpp>
#include <boost/statechart/simple_state.hpp>
#include <boost/statechart/event.hpp>
#include <boost/statechart/transition.hpp>

// states
struct A;
struct B;
struct C;
struct D;

// events
struct S : boost::statechart::event<S> {};
struct T : boost::statechart::event<T> {};
struct U : boost::statechart::event<U> {};

// fsm
struct FSM : boost::statechart::state_machine<FSM, B> {};

// fully defined states/transitions
struct A : boost::statechart::simple_state<A, FSM> {
typedef boost::statechart::transition<S, C> reactions;

A() { std::cout << "entered A" << std::endl; }
};

struct B : boost::statechart::simple_state<B, FSM> {
typedef boost::statechart::transition<S, C> reactions;

B() { std::cout << "entered B" << std::endl; }
};

struct C : boost::statechart::simple_state<C, FSM> {
typedef boost::mpl::list<
boost::statechart::transition<T, A>,
boost::statechart::transition<T, B>,
boost::statechart::transition<U, D> > reactions;

C() { std::cout << "entered C" << std::endl; }
};

struct D : boost::statechart::simple_state<D, FSM> {
D() { std::cout << "entered D" << std::endl; }
};

int main() {
FSM fsm;

fsm.initiate();

fsm.process_event(S());
fsm.process_event(T());
fsm.process_event(S());
fsm.process_event(U());

return 0;
}

Код выше возвращает:

entered B
entered C
entered A
entered C
entered D

и я хотел бы вместо этого увидеть:

entered B
entered C
entered B
entered C
entered D

Есть ли какой-нибудь чистый способ сделать это, используя Boost :: Statechart?

0

Решение

Я нашел ~ хорошо ~ способ сделать это, создав сопоставление enum для состояний, сохранив предыдущее состояние в крайнем контексте (fsm верхнего уровня), а затем используя пользовательскую реакцию для события T:

#include <boost/mpl/list.hpp>

#include <boost/statechart/state_machine.hpp>
#include <boost/statechart/simple_state.hpp>
#include <boost/statechart/event.hpp>
#include <boost/statechart/transition.hpp>
#include <boost/statechart/custom_reaction.hpp>

// states
struct A;
struct B;
struct C;
struct D;

// state enum mapping
enum class state_mapping {
A = 0,
B,
C,
D
};

// events
struct S : boost::statechart::event<S> {};
struct T : boost::statechart::event<T> {};
struct U : boost::statechart::event<U> {};

// fsm
struct FSM : boost::statechart::state_machine<FSM, B> {
state_mapping previous_state = state_mapping::B;
};

// fully defined states/transitions
struct A : boost::statechart::simple_state<A, FSM> {
typedef boost::statechart::transition<S, C> reactions;

A() { std::cout << "entered A" << std::endl; }
virtual ~A() { outermost_context().previous_state = state_mapping::A; }
};

struct B : boost::statechart::simple_state<B, FSM> {
typedef boost::statechart::transition<S, C> reactions;

B() { std::cout << "entered B" << std::endl; }
virtual ~B() { outermost_context().previous_state = state_mapping::B; }
};

struct C : boost::statechart::simple_state<C, FSM> {
typedef boost::mpl::list<
boost::statechart::custom_reaction<T>,
boost::statechart::transition<U, D> > reactions;

C() { std::cout << "entered C" << std::endl; }

boost::statechart::result react(const T&) {

switch(outermost_context().previous_state) {

case state_mapping::A:
return transit<A>();
case state_mapping::B:
return  transit<B>();
default:
return discard_event();

}

}
};

struct D : boost::statechart::simple_state<D, FSM> {
D() { std::cout << "entered D" << std::endl; }
};

int main() {
FSM fsm;

fsm.initiate();

fsm.process_event(S());
fsm.process_event(T());
fsm.process_event(S());
fsm.process_event(U());

return 0;
}

Если у кого-то есть лучшее предложение, я весь слух, иначе я приму это через день или два.

1

Другие решения

Других решений пока нет …