我希望子状态机成为状态机的“initial_state”。以下应该是代码的细分版本。
struct E {
};
struct A : public boost::msm::front::state<> {
template <class TEvent, class TStateMachine>
void on_entry(TEvent const& event, TStateMachine& stateMachine) {
}
template <class TEvent, class TStateMachine>
void on_exit(TEvent const& event, TStateMachine& stateMachine) {
}
};
struct B: public boost::msm::front::state<> {
template <class TStateMachine>
void on_entry(E const& event, TStateMachine& stateMachine) {
}
template <class TStateMachine>
void on_exit(E const& event, TStateMachine& stateMachine) {
}
};
struct SubMachineDefinition : public boost::msm::front::state_machine_def<SubMachineDefinition> {
typedef boost::msm::front::state_machine_def<SubMachineDefinition> Base;
typedef A initial_state;
struct transition_table : boost::mpl::vector<
typename Base::template _row<A, E, B>
> {};
// Added via suggestion of sehe
template <class IE, class SM> void on_entry(IE const&, SM&) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
// Added via suggestion of sehe
template <class IE, class SM> void on_exit (IE const&, SM&) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
};
struct SuperMachineDefinition : public boost::msm::front::state_machine_def<SuperMachineDefinition > {
typedef SubMachineDefinition initial_state;
struct transition_table : boost::mpl::vector<> {};
};
int main() {
boost::msm::back::state_machine<SuperMachineDefinition> states;
states.start();
states.process_event(E()); // This crashes
}
虽然编译得很好,但当我调用process_event
时,它会崩溃。这甚至可能还是有办法调试这个?
我现在在A::on_entry
设置断点。当start
被调用时,它不会中断,所以我明显的问题 - 为什么不使用子状态机??
有趣的是,当我将SubMachineDefinition
替换为boost::msm::back::state_machine<SubMachineDefinition>
(作为initial_state
)时,我收到了编译错误,说明它尝试使用B::on_entry
来调用InitEvent
E
。我现在非常困惑。
实际上我确实为A
复制了错误的重载。我也确实应用了sehe的SubMachineDefinition::on_entry
和SubMachineDefinition::on_exit
定义。仍然,我收到编译错误,它尝试使用B::on_entry
调用InitEvent
。
答案 0 :(得分:3)
正如您已经注意到的那样,您需要将SubMachine
状态设为后端
typedef boost::msm::back::state_machine<SubMachineDefinition> SubMachine;
typedef SubMachine initial_state;
接下来,您需要准备好处理(或忽略)存在的InitEvent
,以便SubMachine
知道是什么使它进入初始状态。
最简单,最典型的方法是模板化事件参数:
struct A : public boost::msm::front::state<> {
template <class IE, class SM> void on_entry(IE const&, SM&) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
template <class IE, class SM> void on_exit (IE const&, SM&) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
};
但是,当然,您可以使用重载来明确处理某些事件:
struct A : public boost::msm::front::state<> {
template <class IE, class SM> void on_entry(IE const&, SM&) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
template <class SM> void on_entry(E const&, SM&) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
template <class IE, class SM> void on_exit (IE const&, SM&) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
};
你可能会像
那样写它template <class SM> void on_entry(typename SM::InitEvent const&, SM&) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
如果不是子状态机,这确实有效。这是因为InitEvent实际上是msm::state_machine<SuperMachineDefinition>::InitEvent
,而不是msm::state_machine<SubMachineDefinition>::InitEvent
。你可以加载一个template-magic来显式检测InitEvent,但是你应该只使用重载,如图所示。
问即可。 如果有人可以向我解释,实现如何在 上搜索其调用InitEvent的状态,那将是非常好的
关键是它/不会/搜索特定的状态来运行它;它使用访问者模式来执行此操作,这意味着静态地,所有子状态必须准备好接受InitEvent
。
运行时日志显示仅调用A::on_entry(InitEvent const&, SM&)
。
你可以简单地“吃”&#34; InitEvent
。 (见上文,关于使用重载)。
最后归结为关注点分离:从超级机器看,子机是不透明的状态。 The same limitation is mentioned in the documentation (#limitation-submachine)关于事件属性:
然而,对于子机器存在限制。如果子机器的子状态具有需要特殊事件属性的入口操作(如给定方法),则编译器将要求进入该子机器的所有事件都支持此属性。
当然,为了处理InitEvent,你不需要 来执行SFINAE魔法,因为你可以对你期望的事件类型进行重载。
问即可。 你能看一下你的结构
B
,为什么不使用E
?这就是原因(作弊),为什么你的例子有效
这不是骗子。您的代码根本不满足对子机器状态on_entry
方法的要求。
既然您已经识别出导致代码出现问题的特定元素,那么接受此作为解决方案的路径可能是明智之举......
完整的示例 Live On Coliru
#include <boost/msm/msm_grammar.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/back/state_machine.hpp>
#include <iostream>
struct E {
};
struct A : public boost::msm::front::state<> {
template <class IE, class SM> void on_entry(IE const&, SM&) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
template <class SM> void on_entry(E const&, SM&) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
template <class IE, class SM> void on_exit (IE const&, SM&) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
};
struct B : public boost::msm::front::state<> {
template <class IE, class SM> void on_entry(IE const&, SM&) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
template <class IE, class SM> void on_exit (IE const&, SM&) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
};
struct SubMachineDefinition : public boost::msm::front::state_machine_def<SubMachineDefinition>
{
typedef boost::msm::front::state_machine_def<SubMachineDefinition> Base;
typedef A initial_state;
struct transition_table : boost::mpl::vector<
typename Base::template _row<A, E, B>,
typename Base::template _row<B, E, A>
> {};
template <class IE, class SM> void on_entry(IE const&, SM&) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
template <class IE, class SM> void on_exit (IE const&, SM&) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
};
struct SuperMachineDefinition : public boost::msm::front::state_machine_def<SuperMachineDefinition > {
typedef boost::msm::back::state_machine<SubMachineDefinition> SubMachine;
typedef SubMachine initial_state;
struct transition_table : boost::mpl::vector<> {};
};
int main() {
boost::msm::back::state_machine<SuperMachineDefinition> states;
states.start();
states.process_event(E());
states.process_event(E());
states.process_event(E());
states.process_event(E());
states.process_event(E());
}