У меня есть общее условие охраны, которое я хотел бы условно предотвратить при определенных обстоятельствах. Ниже приведен несколько C ++ / псевдокод того, что я хотел бы сделать.
bool operator()(Event const& evt, FSM & fsm, SourceState& src, TargetState& tgt )
{
bool transition = (current_state != next_state);
bool transitionAllowed = (x | y | z); //some custom condition
return (transition && transitionAllowed);
}
Я хотел бы знать, отличается ли целевое состояние от исходного состояния и на основании этого определить, можем ли мы разрешить переходы на основе других параметров. До сих пор я не нашел большого успеха с документацией.
Кажется, ваш вопрос состоит из двух частей.
Один из них — как проверить текущее состояние и следующее состояние. Другой способ проверить пользовательские условия.
Для проверки текущего состояния и следующего состояния вы можете использовать std::is_same
мета-функция.
Вот пример охранника:
struct Guard1 {
template <class Event, class Fsm, class Source, class Target>
bool operator()(Event const&, Fsm& fsm, Source& src, Target&) const {
bool transition = !std::is_same<Source, Target>::value;
bool transitionAllowed = x() || fsm.y || src.z;
return transition && transitionAllowed;
}
};
Вот таблица переходов:
// Transition table
struct transition_table:mpl::vector<
// Start Event Next Action Guard
// source and target is the same
msmf::Row < State1, Event1, State1, msmf::none, Guard1 >,
// source and target is different
msmf::Row < State1, Event2, State2, msmf::none, Guard1 >
> {};
Переход, вызванный Event1, имеет одинаковые исходное и целевое состояния. Оба являются State1. Переход, вызванный Event2, имеет разные исходное и целевое состояния. Исходное состояние — State1, а целевое состояние — State2.
Бывший случай std::is_same<Source, Target>::value
возвращает истину, а последний случай возвращает ложь.
Переменная transition
является нагией результата.
Вы можете использовать это как часть возвращаемого значения.
Чтобы оценить пользовательское условие, вам нужно получить значения для оценки из некоторых источников.
Я написал три примера источников.
x()
это глобальная функция. Конечно, вы можете использовать глобальные переменные, как это.y
является переменной-членом конечного автомата.z
переменная-член исходного состояния State1.Вот полный код:
#include <iostream>
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>
#include <boost/static_assert.hpp>
namespace msm = boost::msm;
namespace msmf = boost::msm::front;
namespace mpl = boost::mpl;
// You can test changing the value
bool const example_value = true;
struct Event1 {};
struct Event2 {};
// example of a condition
bool x() { return example_value; }
struct Sm_:msmf::state_machine_def<Sm_>
{
// States
struct State1:msmf::state<> {
template <class Event,class Fsm>
void on_entry(Event const&, Fsm&) const {
std::cout << "State1::on_entry()" << std::endl;
}
template <class Event,class Fsm>
void on_exit(Event const&, Fsm&) const {
std::cout << "State1::on_exit()" << std::endl;
}
bool z = example_value; // example of a condition
};
struct State2:msmf::state<> {
template <class Event,class Fsm>
void on_entry(Event const&, Fsm&) {
std::cout << "State2::on_entry()" << std::endl;
}
template <class Event,class Fsm>
void on_exit(Event const&, Fsm&) const {
std::cout << "State2::on_exit()" << std::endl;
}
int property;
};
// Set initial state
typedef State1 initial_state;
// Guards
struct Guard1 {
template <class Event, class Fsm, class Source, class Target>
bool operator()(Event const&, Fsm& fsm, Source& src, Target&) const {
bool transition = !std::is_same<Source, Target>::value;
bool transitionAllowed = x() || fsm.y || src.z;
return transition && transitionAllowed;
}
};
// Transition table
struct transition_table:mpl::vector<
// Start Event Next Action Guard
// source and target is the same
msmf::Row < State1, Event1, State1, msmf::none, Guard1 >,
// source and target is different
msmf::Row < State1, Event2, State2, msmf::none, Guard1 >
> {};
bool y = example_value; // example of a condition
};
// Pick a back-end
typedef msm::back::state_machine<Sm_> Sm;
int main() {
Sm sm;
sm.start();
std::cout << "> Send Event1()" << std::endl;
sm.process_event(Event1());
std::cout << "> Send Event2()" << std::endl;
sm.process_event(Event2());
}
Вы можете изменить значения пользовательских условий.
// You can test changing the value
bool const example_value = true;
Если для параметра example_value задано значение false, пользовательское условие не выполняется.
Если пользовательское условие НЕ выполняется, оба Event1
а также Event2
не делайте переход.
Если пользовательские условия удовлетворены, Event1
не выполняет переход, потому что исходное и целевое состояния совпадают. Event2
делает переход.
Вот бегущая демка.
Дело example_value = true
https://wandbox.org/permlink/6qHcW9e6JX4QXAuH
Дело example_value = false
Других решений пока нет …