boost::msm中实现全状态转换通用行为的最优方案
在boost::msm中实现全局状态转换通用行为的最优方式
boost::msm本身没有内置的全局默认转换机制,但可以通过以下几种简洁可靠的方式实现任意状态转换时执行通用函数的需求:
1. 基于转换动作(Transition Action)的全局基类
这是最直接且符合msm设计思路的方式:定义一个包含通用转换逻辑的基类动作,所有具体转换的动作都继承该基类。这样每次触发转换时,动作执行都会先调用基类的通用逻辑。
示例代码:
#include <boost/msm/front/state_machine_def.hpp> #include <boost/msm/back/state_machine.hpp> #include <iostream> // 通用转换动作基类 struct BaseTransitionAction { template <class Event, class FSM, class SourceState, class TargetState> void operator()(Event const&, FSM&, SourceState& src, TargetState& dst) { // 这里放置你需要在所有转换时执行的通用逻辑 std::cout << "通用转换逻辑执行: 从" << typeid(src).name() << "到" << typeid(dst).name() << "\n"; } }; // 具体转换动作:继承基类,可添加自定义逻辑 struct CustomAction : BaseTransitionAction { using BaseTransitionAction::operator(); // 继承基类的operator() // 可选:重写或扩展特定逻辑 template <class Event, class FSM, class SourceState, class TargetState> void operator()(Event const&, FSM&, SourceState& src, TargetState& dst) { BaseTransitionAction::operator()(std::declval<Event>(), std::declval<FSM>(), src, dst); // 先执行通用逻辑 // 添加当前转换的自定义逻辑 std::cout << "自定义转换逻辑执行\n"; } }; // 事件定义 struct Event1 {}; struct Event2 {}; // 状态机前端定义 struct FsmFront : boost::msm::front::state_machine_def<FsmFront> { struct State1 : boost::msm::front::state<> {}; struct State2 : boost::msm::front::state<> {}; // 初始状态 using initial_state = State1; // 转换表:使用自定义动作(继承了通用逻辑) struct transition_table : boost::mpl::vector< // 源状态, 事件, 目标状态, 动作, 守卫 boost::msm::front::Row<State1, Event1, State2, CustomAction, boost::msm::front::none>, boost::msm::front::Row<State2, Event2, State1, BaseTransitionAction, boost::msm::front::none> > {}; }; // 状态机后端 using Fsm = boost::msm::back::state_machine<FsmFront>;
2. 全局转换守卫(Guard)的基类
如果需要在转换执行前触发通用逻辑(比如权限检查、日志记录),可以用守卫的基类方式。守卫返回true才允许转换,适合前置逻辑。
示例代码:
struct BaseTransitionGuard { template <class Event, class FSM, class SourceState, class TargetState> bool operator()(Event const& evt, FSM&, SourceState&, TargetState&) { // 通用前置逻辑 std::cout << "转换前置检查: 事件" << typeid(evt).name() << "\n"; return true; // 允许转换 } }; // 具体转换守卫 struct CustomGuard : BaseTransitionGuard { using BaseTransitionGuard::operator(); template <class Event, class FSM, class SourceState, class TargetState> bool operator()(Event const& evt, FSM& fsm, SourceState& src, TargetState& dst) { if (!BaseTransitionGuard::operator()(evt, fsm, src, dst)) return false; // 自定义检查逻辑 return true; } }; // 在转换表中使用 boost::msm::front::Row<State1, Event1, State2, CustomAction, CustomGuard>
3. 状态机的事件处理钩子
如果希望在事件进入状态机后、转换执行前后触发逻辑,可以重载状态机前端的preprocess_event或postprocess_event方法:
struct FsmFront : boost::msm::front::state_machine_def<FsmFront> { // ... 状态和转换表定义 ... // 事件预处理:在事件被状态机接收后、转换执行前调用 template <class Event> void preprocess_event(Event const& evt) { std::cout << "事件预处理: " << typeid(evt).name() << "\n"; } // 事件后处理:在转换执行完成后调用 template <class Event> void postprocess_event(Event const& evt) { std::cout << "事件后处理: " << typeid(evt).name() << "\n"; } };
注意:这种方式是针对所有事件的,不管是否触发有效转换,适合全局事件级别的逻辑,而非严格的状态转换触发逻辑。
总结
- 若需要严格绑定状态转换的通用逻辑,优先使用转换动作基类,完全贴合msm的转换模型;
- 若需要转换前置检查逻辑,用守卫基类;
- 若需要全局事件级别的前后处理,用状态机的钩子方法。
内容的提问来源于stack exchange,提问作者Tomasz
相关产品推荐
相关产品推荐

