子状态机作为boost :: msm中的初始活动状态

时间:2014-10-01 13:49:03

标签: visual-studio-2010 boost state-machine c++98 boost-msm

我希望子状态机成为状态机的“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时,它会崩溃。这甚至可能还是有办法调试这个?

编辑1:

我现在在A::on_entry设置断点。当start被调用时,它不会中断,所以我明显的问题 - 为什么不使用子状态机??

编辑2:

有趣的是,当我将SubMachineDefinition替换为boost::msm::back::state_machine<SubMachineDefinition>(作为initial_state)时,我收到了编译错误,说明它尝试使用B::on_entry来调用InitEvent E。我现在非常困惑。

编辑3:

实际上我确实为A复制了错误的重载。我也确实应用了sehe的SubMachineDefinition::on_entrySubMachineDefinition::on_exit定义。仍然,我收到编译错误,它尝试使用B::on_entry调用InitEvent

1 个答案:

答案 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());
}