読者です 読者をやめる 読者になる 読者になる

Boost.Statechartを簡単に使うためのabstract_fsm

C++

abstract_fsm – finite state machines in C++


これいいですね。
通常、Boost.Statechartを使うとこれだけのコード量になってしまうのが

#include <boost/statechart/event.hpp>
#include <boost/statechart/state_machine.hpp>
#include <boost/statechart/simple_state.hpp>
#include <boost/statechart/transition.hpp>

struct Play : boost::statechart::event<Play> {};
struct Stop : boost::statechart::event<Stop> {};
struct Stopped; struct Playing;
struct Machine : boost::statechart::state_machine<Machine, Stopped> {
    void actStoppedPlayPlaying(const Play& evt)
        { std::cout << "starting to play" << std::endl; }

    void actStoppedStopStopped(const Stop& evt)
        { std::cout << "stopping" << std::endl; }

    void actPlayingStopStopped(const Stop& evt)
        { std::cout << "staying in Stopped" << std::endl; }
};
struct Stopped : boost::statechart::simple_state<Stopped, Machine> {
    typedef boost::mpl::list<
        boost::statechart::transition<Play, Playing, Machine, &Machine::actStoppedPlayPlaying>,
        boost::statechart::transition<Stop, Stopped, Machine, &Machine::actStoppedStopStopped>
    reactions;
};

struct Playing : boost::statechart::simple_state<Playing, Machine> {
    typedef
        boost::mpl::list< boost::statechart::transition<Stop, Stopped, Machine, &Machine::actPlayingStopStopped> >
    reactions;
};

int main(int argc, const char* argv[])
{
    Machine mach;
    mach.initiate();
    mach.process_event(Stop());
    mach.process_event(Play());
    mach.process_event(Stop());
}


これらの状態クラスを自動生成するFSM_DEFマクロを使うとこれだけで済みます。

#include <iostream>
#include "abstract_fsm.h"

FSM_DEF(Machine, // The type of the FSM
    (Play)(Stop), // the events
    // The transitions (including the states)
    ((Stopped,
        ((Play, Playing, { std::cout << "starting to play" << std::endl; }))
        ((Stop, Stopped, { std::cout << "stopping" << std::endl; }))))
        ((Playing, ((Stop, Stopped, { std::cout << "staying in Stopped" << std::endl; }))))
    )

int main(int argc, const char* argv[])
{
    Machine mach;
    mach.initiate();
    mach.process_event(Stop());
    mach.process_event(Play());
    mach.process_event(Stop());
}


現在レビュー中のBoost.MSM(Meta State Machine)にも対応しているようで、
プリプロセスのオプションを変更すれば以下のコードが出力されるそうです。

#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>

struct Play {};
struct Stop {};
struct Stopped : boost::msm::front::state<> {};
struct Playing : boost::msm::front::state<> {};
struct Machine_ : boost::msm::front::state_machine_def<Machine_> {
    typedef Stopped initial_state;

    void actStoppedPlayPlaying(const Play& evt)
        { std::cout << "starting to play" << std::endl; }

    void actStoppedStopStopped(const Stop& evt)
        { std::cout << "stopping" << std::endl; }

    void actPlayingStopStopped(const Stop& evt)
        { std::cout << "staying in Stopped" << std::endl; }

    typedef boost::mpl::vector<
        a_row<Stopped, Play, Playing, &Machine_::actStoppedPlayPlaying>,
        a_row<Stopped, Stop, Stopped, &Machine_::actStoppedStopStopped>,
        a_row<Playing, Stop, Stopped, &Machine_::actPlayingStopStopped>
    transition_table;

    void initiate() {}
};

typedef boost::msm::back::state_machine<Machine_> Machine;

int main(int argc, const char* argv[])
{
    Machine mach;
    mach.initiate();
    mach.process_event(Stop());
    mach.process_event(Play());
    mach.process_event(Stop());
}