【问题标题】:Boost msm Sub-Sub-Statemachine提升 msm 子子状态机
【发布时间】:2016-02-22 16:48:03
【问题描述】:

我在使用 boost::msm 实现子子状态机时遇到了一些麻烦。 我正在尝试在这里最小化我的代码...

Test.cpp:

struct SM_ : StateMachineA<SM_> {};
// Pick a back-end
typedef boost::msm::back::state_machine<SM_> SM;
int main()
{
    std::cout << "Starting State Machine" << std::endl;
    SM sm1;
    //  sm1.start();
    return 0;
}

StateMachineA 在 StateMachineA.h 中定义

namespace msmf = boost::msm::front;
namespace mpl = boost::mpl;
template<typename Derived>
struct StateMachineA: protected msmf::state_machine_def < Derived, msmf::default_base_state >
        {
        public:

            //// Entry point to state machine. 

            //// Set initial state
            typedef mpl::vector<initState, allOk> initial_state;

            //// Exit Point
            struct Exit :msmf::terminate_state<> {};

            // ----- Sub State machine
            struct SSM_ : StateMachineB<SSM_> {};

            // Pick a back-end
            typedef boost::msm::back::state_machine<SSM_> stateMachineB;


            //// Transition table
            struct transition_table : mpl::vector<
                msmf::Row < initState, go, stateMachineB, msmf::none, msmf::none >,
                msmf::Row < allOk, fatalThrown, Exit, msmf::none, msmf::none >,
                msmf::Row < error, fatalThrown, Exit, msmf::none, msmf::none >
            > {};




        protected:


            template <class FSM, class Event>
            void no_transition(Event const&, FSM&, int)
            {
                std::cout << "ERROR: Unallowed transition detected" << std::endl;
            }
        };

StateMachineB 包含一个使用完全相同的代码的 StateMachineC(将 B 替换为 C...)。

将 StateMachineC 作为 StateMachineA 的子机(省略 StateMachineB)可以正常工作。相同的 A -> B 不包括 C 也可以正常工作。重新排序状态机 (A -> C -> B) 会产生相同的错误。总结一下:两个状态机的每个组合都在工作,三个状态机的每个组合都失败了。 当我的主函数中有SM sm1; 时会发生错误。 -> 在解析模板时? 没有那行,一切都编译得很好。

错误日志很长(长到足以导致 Visual Studio 在悬停时崩溃...)。第一个错误是:

D:\boost_1_59_0\boost/mpl/aux_/push_front_impl.hpp(45) : error C2664: 'int    boost::mpl::assertion_failed<false>(boost::mpl::assert<false>::type)' : cannot convert argument 1 from 'boost::mpl::failed ************(__thiscall boost::mpl::push_front_impl<boost::mpl::aux::vector_tag<20>>::apply<Sequence,T>::REQUESTED_PUSH_FRONT_SPECIALIZATION_FOR_SEQUENCE_DOES_NOT_EXIST::* ***********)(Sequence)' to 'boost::mpl::assert<false>::type'

与 ...以及大约 200 行“与”行。 之后,许多类型的错误:

D:\boost_1_59_0\boost/mpl/aux_/insert_impl.hpp(60) : error C3203: 'type' : unspecialized class template can't be used as a template argument for template parameter 'State', expected a real type
D:\boost_1_59_0\boost/mpl/insert.hpp(32) : error C2903: 'apply' : symbol is neither a class template nor a function template
    D:\boost_1_59_0\boost/mpl/aux_/has_type.hpp(20) : see reference to class template instantiation 'boost::mpl::insert<U1,U2,U3>' being compiled

关注。

有什么想法吗?

谢谢!

【问题讨论】:

    标签: c++ boost boost-msm


    【解决方案1】:

    我无法重现您的情况,但我可以向您展示如何实现 SubSub 状态机。 这是我写的一个文件。它描述了子状态机。 http://redboltz.wikidot.com/sub-machine-state

    要实现 SubSub 状态机,只需应用两次子机实现即可。

    这是一个包含 SubSub 状态机的代码:

    #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;
    
    // StateMachine [Osm]
    //
    // (initial)
    //    |
    //    V
    // State1:StateSub --Event1--> State2
    //
    //
    // StateMachine [StateSub]
    //
    // (initial)
    //    |
    //    V
    // SubState1 --Event2--> SubState2:StateSubSub
    //    A                          |
    //    +--------Event3------------+
    //
    //
    // StateMachine [StateSubSub]
    //
    // (initial)
    //    |
    //    V
    // SubSubState1---Event4--> SubSubState2
    //    A                          |
    //    +-----------Event5---------+
    
    
    
    // ----- Events
    struct Event1 {};
    struct Event2 {};
    struct Event3 {};
    struct Event4 {};
    struct Event5 {};
    
    // ----- State machine
    struct StateSubSub_:msmf::state_machine_def<StateSubSub_>
    {
        struct SubSubState1:msmf::state<> {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, StateSubSub_>::value));
                std::cout << "SubSubState1::on_entry()" << std::endl;
            }
            template <class Event,class Fsm>
            void on_exit(Event const&, Fsm&) const {
                BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, StateSubSub_>::value));
                std::cout << "SubSubState1::on_exit()" << std::endl;
            }
        };
        struct SubSubState2:msmf::state<> {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, StateSubSub_>::value));
                std::cout << "SubSubState2::on_entry()" << std::endl;
            }
            template <class Event,class Fsm>
            void on_exit(Event const&, Fsm&) const {
                BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, StateSubSub_>::value));
                std::cout << "SubSubState2::on_exit()" << std::endl;
            }
        };
    
        // Set initial state
        typedef mpl::vector<SubSubState1> initial_state;
        // Transition table
        struct transition_table:mpl::vector<
            //          Start      Event   Next       Action      Guard
            msmf::Row < SubSubState1, Event4, SubSubState2, msmf::none, msmf::none >,
            msmf::Row < SubSubState2, Event5, SubSubState1, msmf::none, msmf::none >
        > {};
    };
    typedef msm::back::state_machine<StateSubSub_> StateSubSub;
    
    
    // ----- State machine
    struct StateSub_:msmf::state_machine_def<StateSub_>
    {
        struct SubState1:msmf::state<> {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, StateSub_>::value));
                std::cout << "SubState1::on_entry()" << std::endl;
            }
            template <class Event,class Fsm>
            void on_exit(Event const&, Fsm&) const {
                BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, StateSub_>::value));
                std::cout << "SubState1::on_exit()" << std::endl;
            }
        };
        struct SubState2_:msmf::state_machine_def<SubState2_>
        {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, StateSub_>::value));
                std::cout << "SubState2::on_entry()" << std::endl;
            }
            template <class Event,class Fsm>
            void on_exit(Event const&, Fsm&) const {
                BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, StateSub_>::value));
                std::cout << "SubState2::on_exit()" << std::endl;
            }
            struct Impl_:StateSubSub {};
            typedef Impl_ initial_state;
        };
        // Pick a back-end
        typedef msm::back::state_machine<SubState2_> SubState2;
    
        // Set initial state
        typedef mpl::vector<SubState1> initial_state;
        // Transition table
        struct transition_table:mpl::vector<
            //          Start      Event   Next       Action      Guard
            msmf::Row < SubState1, Event2, SubState2, msmf::none, msmf::none >,
            msmf::Row < SubState2, Event3, SubState1, msmf::none, msmf::none >
        > {};
    };
    typedef msm::back::state_machine<StateSub_> StateSub;
    
    struct OuterSm_:msmf::state_machine_def<OuterSm_>
    {
        struct State1_:msmf::state_machine_def<State1_>
        {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, OuterSm_>::value));
                std::cout << "State1::on_entry()" << std::endl;
            }
            template <class Event,class Fsm>
            void on_exit(Event const&, Fsm&) const {
                BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, OuterSm_>::value));
                std::cout << "State1::on_exit()" << std::endl;
            }
            struct Impl_:StateSub {};
            typedef Impl_ initial_state;
        };
        // Pick a back-end
        typedef msm::back::state_machine<State1_> State1;
        struct State2:msmf::state<>
        {
            template <class Event,class Fsm>
            void on_entry(Event const&, Fsm&) const {
                BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, OuterSm_>::value));
                std::cout << "State2::on_entry()" << std::endl;
            }
            template <class Event,class Fsm>
            void on_exit(Event const&, Fsm&) const {
                BOOST_STATIC_ASSERT((boost::is_convertible<Fsm, OuterSm_>::value));
                std::cout << "State2::on_exit()" << std::endl;
            }
        };
        // Set initial state
        typedef State1 initial_state;
        // Transition table
        struct transition_table:mpl::vector<
            //          Start   Event   Next    Action      Guard
            msmf::Row < State1, Event1, State2, msmf::none, msmf::none >
        > {};
    };
    
    // Pick a back-end
    typedef msm::back::state_machine<OuterSm_> Osm;
    
    void test()
    {
        Osm osm;
        osm.start();
    
        std::cout << "> Send Event2()" << std::endl;
        osm.process_event(Event2());
        std::cout << "> Send Event4()" << std::endl;
        osm.process_event(Event4());
        std::cout << "> Send Event5()" << std::endl;
        osm.process_event(Event5());
        std::cout << "> Send Event3()" << std::endl;
        osm.process_event(Event3());
        std::cout << "> Send Event1()" << std::endl;
        osm.process_event(Event1());
    }
    
    int main()
    {
        test();
    }
    

    您可以在 Wandbox 在线编译器上编译、运行和修改它。

    http://melpon.org/wandbox/permlink/tBCSQDNhkBQkXxh0

    【讨论】:

    • 您好,非常感谢您的回答。我已经在 redboltz 找到了该条目并经常使用它。也谢谢你!
    • 您好,非常感谢您的回答。我已经在 redboltz 找到了该条目并经常使用它。也谢谢你!我遇到的一个问题是 mpl::vector 的限制。在将子机添加到状态机时,我认为向量会在内部合并到更大的转换表中。因此,所有转换的总和必须低于限制,而不仅仅是每个状态机的转换数量。我合并了两个状态机,错误更有意义。不确定我是否在合并过程中修复了其他问题....
    • 我认为 mpl::vector 的限制分别适用于每个状态机。请参阅melpon.org/wandbox/permlink/SK5dIbEiSXi6pqHk 我将最大 mpl::vector 大小限制为 10。每个(子)状态机都有一个包含 10 个元素的转换表。
    • 好的,在那种情况下,我必须更正s.th。在合并两个状态机时无意中...我将检查版本历史记录,看看是否能找到问题。非常感谢您的帮助!
    • 此代码加一个,因为 boost 1.61 的文档已经完全过时,包括示例在内,都是不正确的。谢谢!
    猜你喜欢
    • 2013-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多