Boost - 해당되는 글 1건

정리가 필요하다

Basic front-end

     이것은 MPL book으로부터 상속된 유명한 front-end 이다. 이것은 다른 이름들과 기능들로 이루어진 전이 테이블을 제공한다.

      Actions 과 Guards 는 전이 포인터를 통해 레퍼런스와 함수처럼 정의 된다. 이 front-end는 상태 머신을 쉽게 정의하여 만들수 있게 간단한 인터페이스를 제공한다.

     그러나 더 복잡한 상태 머신은 만들기 어렵다.

// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

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

namespace msm = boost::msm;
namespace mpl = boost::mpl;

namespace
{
    // events
    struct play {};
    struct end_pause {};
    struct stop {};
    struct pause {};
    struct open_close {};

    // A "complicated" event type that carries some data.
        enum DiskTypeEnum
    {
        DISK_CD=0,
        DISK_DVD=1
    };
    struct cd_detected
    {
        cd_detected(std::string name, DiskTypeEnum diskType)
            : name(name),
            disc_type(diskType)
        {}

        std::string name;
        DiskTypeEnum disc_type;
    };

    // front-end: define the FSM structure 
    struct player_ : public msm::front::state_machine_def<player_>
    {
        template <class Event,class FSM>
        void on_entry(Event const& ,FSM&) 
        {
            std::cout << "entering: Player" << std::endl;
        }
        template <class Event,class FSM>
        void on_exit(Event const&,FSM& ) 
        {
            std::cout << "leaving: Player" << std::endl;
        }

        // The list of FSM states
        struct Empty : public msm::front::state<> 
        {
            // every (optional) entry/exit methods get the event passed.
            template <class Event,class FSM>
            void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
            template <class Event,class FSM>
            void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
        };
        struct Open : public msm::front::state<> 
        {        
            template <class Event,class FSM>
            void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
            template <class Event,class FSM>
            void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
        };

        // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
        struct Stopped : public msm::front::state<msm::front::default_base_state,msm::front::sm_ptr> 
        {        
            template <class Event,class FSM>
            void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
            template <class Event,class FSM>
            void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
            void set_sm_ptr(player_* pl)
            {
                m_player=pl;
            }
            player_* m_player;
        };

        struct Playing : public msm::front::state<>
        {
            template <class Event,class FSM>
            void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
            template <class Event,class FSM>
            void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
        };

        // state not defining any entry or exit
        struct Paused : public msm::front::state<>
        {
        };

        // the initial state of the player SM. Must be defined
        typedef Empty initial_state;

        // transition actions
        void start_playback(play const&)       { std::cout << "player::start_playback\n"; }
        void open_drawer(open_close const&)    { std::cout << "player::open_drawer\n"; }
        void close_drawer(open_close const&)   { std::cout << "player::close_drawer\n"; }
        void store_cd_info(cd_detected const&) { std::cout << "player::store_cd_info\n"; }
        void stop_playback(stop const&)        { std::cout << "player::stop_playback\n"; }
        void pause_playback(pause const&)      { std::cout << "player::pause_playback\n"; }
        void resume_playback(end_pause const&)      { std::cout << "player::resume_playback\n"; }
        void stop_and_open(open_close const&)  { std::cout << "player::stop_and_open\n"; }
        void stopped_again(stop const&)     {std::cout << "player::stopped_again\n";}
        // guard conditions
        bool good_disk_format(cd_detected const& evt)
        {
            // to test a guard condition, let's say we understand only CDs, not DVD
            if (evt.disc_type != DISK_CD)
            {
                std::cout << "wrong disk, sorry" << std::endl;
                return false;
            }
            return true;
        }
        // used to show a transition conflict. This guard will simply deactivate one transition and thus
        // solve the conflict
        bool auto_start(cd_detected const&)
        {
            return false;
        }

        typedef player_ p; // makes transition table cleaner

        // Transition table for player
        struct transition_table : mpl::vector<
            //    Start     Event         Next      Action                               Guard
            //  +---------+-------------+---------+---------------------+----------------------+
          a_row < Stopped , play        , Playing , &p::start_playback                         >,
          a_row < Stopped , open_close  , Open    , &p::open_drawer                            >,
           _row < Stopped , stop        , Stopped                                              >,
            //  +---------+-------------+---------+---------------------+----------------------+
          a_row < Open    , open_close  , Empty   , &p::close_drawer                           >,
            //  +---------+-------------+---------+---------------------+----------------------+
          a_row < Empty   , open_close  , Open    , &p::open_drawer                            >,
            row < Empty   , cd_detected , Stopped , &p::store_cd_info   ,&p::good_disk_format  >,
            row < Empty   , cd_detected , Playing , &p::store_cd_info   ,&p::auto_start        >,
            //  +---------+-------------+---------+---------------------+----------------------+
          a_row < Playing , stop        , Stopped , &p::stop_playback                          >,
          a_row < Playing , pause       , Paused  , &p::pause_playback                         >,
          a_row < Playing , open_close  , Open    , &p::stop_and_open                          >,
            //  +---------+-------------+---------+---------------------+----------------------+
          a_row < Paused  , end_pause   , Playing , &p::resume_playback                        >,
          a_row < Paused  , stop        , Stopped , &p::stop_playback                          >,
          a_row < Paused  , open_close  , Open    , &p::stop_and_open                          >
            //  +---------+-------------+---------+---------------------+----------------------+
        > {};
        // Replaces the default no-transition response.
        template <class FSM,class Event>
        void no_transition(Event const& e, FSM&,int state)
        {
            std::cout << "no transition from state " << state
                << " on event " << typeid(e).name() << std::endl;
        }
    };
    // Pick a back-end
    typedef msm::back::state_machine<player_> player;

    //
    // Testing utilities.
    //
    static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
    void pstate(player const& p)
    {
        std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
    }

    void test()
    {        
                player p;
        // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
        p.start(); 
        // go to Open, call on_exit on Empty, then action, then on_entry on Open
        p.process_event(open_close()); pstate(p);
        p.process_event(open_close()); pstate(p);
        // will be rejected, wrong disk type
        p.process_event(
            cd_detected("louie, louie",DISK_DVD)); pstate(p);
        p.process_event(
            cd_detected("louie, louie",DISK_CD)); pstate(p);
                p.process_event(play());

        // at this point, Play is active      
        p.process_event(pause()); pstate(p);
        // go back to Playing
        p.process_event(end_pause());  pstate(p);
        p.process_event(pause()); pstate(p);
        p.process_event(stop());  pstate(p);
        // event leading to the same state
        // no action method called as it is not present in the transition table
        p.process_event(stop());  pstate(p);
        std::cout << "stop fsm" << std::endl;
        p.stop();
    }
}

int main()
{
    test();
    return 0;
}

     우리가 지금 Build 하려고 하는 Meta state machine의 Basic front-end 이다. 



Transition table( 전이 테이블 )

     앞서 언급한, MSM 은 전이 테이블을 기본적으로 아래와 같이 정의할 수 있다.

struct transition_table : mpl::vector<
//    Start     Event        Target      Action                      Guard 
//   +---------+------------+-----------+---------------------------+----------------------------+ 
a_row< Stopped , play       ,  Playing  , &player_::start_playback                               >,
a_row< Stopped , open_close ,  Open     , &player_::open_drawer                                  >,
 _row< Stopped , stop       ,  Stopped                                                           >,
//   +---------+------------+-----------+---------------------------+----------------------------+ 
a_row< Open    , open_close ,  Empty    , &player_::close_drawer                                 >,
//   +---------+------------+-----------+---------------------------+----------------------------+ 
a_row< Empty   , open_close ,  Open     , &player_::open_drawer                                  >,
  row< Empty   , cd_detected,  Stopped  , &player_::store_cd_info   , &player_::good_disk_format >,
  row< Empty   , cd_detected,  Playing  , &player_::store_cd_info   , &player_::auto_start       >,
//   +---------+------------+-----------+---------------------------+----------------------------+ 
a_row< Playing , stop       ,  Stopped  , &player_::stop_playback                                >,
a_row< Playing , pause      ,  Paused   , &player_::pause_playback                               >,
a_row< Playing , open_close ,  Open     , &player_::stop_and_open                                >,
//   +---------+------------+-----------+---------------------------+----------------------------+ 
a_row< Paused  , end_pause  ,  Playing  , &player_::resume_playback                              >,
a_row< Paused  , stop       ,  Stopped  , &player_::stop_playback                                >,
a_row< Paused  , open_close ,  Open     , &player_::stop_and_open                                >
//   +---------+------------+-----------+---------------------------+----------------------------+ 
> {};


     전이 테이블은에서 유일하게 바뀌는것은 다른 타입의 전이 테이블이다. 기본 예제에서는 하나의 Action을 강제로 정의해야 하고 Guard는 없어도 상관 없다.

     Action : State 가 바뀌었을때 호출하는 함수 속성

     Guard : 시작 상태에서 목표 상태로 바뀌기 전에 변경이 가능한지 Guard 조건식을 통해 체크하는 함수 속성

     기본적으로 4개의 row 타입이 있다.

     - row 는 5개의 매개변수를 갖는다 : 시작 상태, 전이 이벤트, 목표 상태, Action 그리고 Guard
     - a_row 는 Action만 정의 하도록 허용된다. Guard 조건은 제외한다.
     - g_row 는 Action을 제외하고 Guard만 정의하도록 한다.
     - _row 는 Action과 Guard 를 제외한다.

     Action 은 void 함수이름( event const& ) 형태로 아래와 같이 사용할 수 있다.

void stop_playback(stop const&)

     

     Guard 는 bool 함수이름( event const& ) 형태로 아래와 같이 사용 할 수 있다.


bool good_disk_format(cd_detected const& evt)


     전이 테이블은 실제로 MPL 벡터 이다. 테이블은 기본으로 최대 20개를 한도로 제공한다.

     만약 더 많은 전이가 필요하다면, 기본 동작의 재정의가 필요하다. 헤더파일을 포함하기 전에 필요한 것을 추가한다.

#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
#define BOOST_MPL_LIMIT_VECTOR_SIZE 30 //or whatever you need                       
#define BOOST_MPL_LIMIT_MAP_SIZE 30 //or whatever you need      

     
     다른 제한은 MPL 타입을 50개의 항목으로 정의 한것 이다. 유일한 해결은 MPL에 헤더를 더 많이 추가해 달성하는것이다(?)( 운좋게도, 매우 복잡하지는 않다. )


Defining states with entry/exit actions( 상태의 입장/퇴장 행동 정의 )


     상태를 MPL book에 열거하면, 그것들은 이제 클래스이다. 그들은 데이터를 보유할 수 있고, 입장/퇴장 행동이 제공된다. 그리고 재사용 가능하게 된다.

     상태를 정의하고, 원하는 상태 타입으로부터 상속 받고, 당신은 주로 간단한 상태를 사용할 것 이다.

     struct Empty : public msm::front::state<> {};

     그들은 입장/퇴장 행동을 선택적으로 제공할 수 있다. ( 대체 무슨말인지.. )

struct Empty : public msm::front::state<> 
{
    template <class Event, class Fsm> 
    void on_entry(Event const&, Fsm& ) 
    {std::cout <<"entering: Empty" << std::endl;} 
    template <class Event, class Fsm> 
    void on_exit(Event const&, Fsm& ) 
    {std::cout <<"leaving: Empty" << std::endl;} 
};


     entry와 exit는 이벤트와 State Machine이 템플릿으로 되었다는 것을 알려준다. 일반적인 재사용이 용이하다는 것. 거기에는 UML 기본 상태 타입과 일치하는 더 많은 상태 타입이 있다( terminate, interrupt, pseudo states, etc...)

     그것들은 다음 섹션에서 상세하게 설명되어 있을 것이다.


What do you actually do inside actions / guards ? ( 실제 내부의 actions / guards 는 무슨 동작을 합니까? )

     상태 머신은 구조체와 완료 행동의 중요한 부분을 정의한다. 하지만 이게 다는 아니다. 

     예제에서 당신이 로켓을 알파 켄타우르스로 보내는것이 필요하면, 당신은 "SendRocketToAlphaCentauri" 로 전의되는 상태를 가질수 있습니다.

     그러나 실제로 로켓을 보내는 코드는 없습니다. 이것은 당신이 필요한 Action에 있습니다. So 간단한 액션이 될 수 있습니다.

     
template <class Fire> void send_rocket(Fire const&)
{
  fire_rocket();
}


     좋습니다. 간단하죠. 이제, 우리는 방향이 주어지길 원합니다. 우리는 이 정보가 필요한 경우 외부에서 주어진다고 가정합니다. 그것은 send_rocket의 이벤트로 사용했을 때 의미가 있습니다.

     
// Event
struct Fire {Direction direction;};
template <class Fire> void send_rocket(Fire const& evt)
{
  fire_rocket(evt.direction);
}


     우리는 계산하길 원해요 방향을 기본으로, 유일하지 않은 외부데이터 뿐만 아니라 이전에 작업에서 축적된 데이터를 통해서

     이 경우, 당신은 상태머신 그 자체안에 이 데이터를 가지길 원해요. 전이 행동이 front-end의 멤버인것처럼. 당신은 데이터에 직접 접근 할수 있어요

     
// Event
struct Fire {Direction direction;};
//front-end definition, see down
struct launcher_ : public msm::front::state_machine_def<launcher_>{
Data current_calculation; 
template <class Fire> void send_rocket(Fire const& evt)
{
  fire_rocket(evt.direction, current_calculation);
}
...
};



     입장과 퇴장 행동은 공통 상태 행동을 표현해요. 전이에 들어갔거나, 떠나는 것을 통해 문제가 없어요. 상태의 재사용, 당신의 데이터를 상태 머신안에 대신 위치하는것은 의미가 있어요.

     최대한 재사용 하거나 좀 더 읽기 쉬운 코드를 만들어요. 입장과 퇴장 행동은 접근 가능한 상태 데이터를 가질수 있지만 또 전이 행동과 같이 이벤트와 상태 머신도 접근할 수 있어요(?)

     이것은 이벤트와 FSM 파라매터를 통해 일어나요


struct Launching : public msm::front::state<> 
{
    template <class Event, class Fsm> 
    void on_entry(Event const& evt, Fsm& fsm) 
    {
       fire_rocket(evt.direction, fsm.current_calculation);
    } 
};


     퇴장 행동은 또 상태가 비활성화 될때 정리의 이상적이에요.

     입장 행동은 하위 상태 / 하위 상태 머신에 데이터를 전달하는 식으로 또 다르게 사용 가능해요. 

     실행은 하위 상태의 데이터 속성을 포함하고 있어요.

   
struct launcher_ : public msm::front::state_machine_def<launcher_>{
Data current_calculation;
// state machines also have entry/exit actions 
template <class Event, class Fsm> 
void on_entry(Event const& evt, Fsm& fsm) 
{
   launcher_::Launching& s = fsm.get_state<launcher_::Launching&>();
   s.data = fsm.current_calculation;
} 
...
};


     set_states back-end 함수는 당신이 완료 상태를 교체하는것을 허용합니다.

     이 functor front-end 와 eUML 은 더 많은 기능을 제공합니다.

     그러나, 이 기본 front-end 또한 row2 / irow2 전이를 사용하는 특수한 기능을 가지고 있습니다.

     당신이 현재 fsm 또는 front-end 안의 어떤 상태를 위치하는 행동을 호출해봅시다. 당신이 보는 적당한 곳에 사용하기 좋은 데이터를 놓습니다.


Defining a simple state machine( 간단한 상태 머신 정의 )


     간단하게 CD 플레이어 상태 머신을 다음과 같이 정의했다.
     
struct player_ : public msm::front::state_machine_def<player_>{
                            /* see below */}

     
     이 정의된 상태 머신은 기본적인 front-end에 사용된다.

typedef Empty initial_state;

     절대적으로 필요한 초기화 상태 머신의 정의. 예제에서 상태는 가독성을 위해 상태 머신 내부에 정의되었지만 이것이 꼭 요구되는 조건은 아니다. 상태들은 당신이 원하는곳 어디에든 정의할 수 있다.

     pick a back-end에서 하는 것은 모두 무엇일까     
typedef msm::back::state_machine<player_> player;

     당신은 이제 상태머신을 사용할 수 있습니다. 입장/퇴장 행동, Guards, 전이 행동들,  이벤트 처리로 다른 이벤트를 발생시킬 수도 있는 상태 머신 뭐 그런것

     상태 머신은 이 간단한 예제에서 사용할 수 없는 삭제된 거의 모든 특색을 당신의 필요에 의해 적용 할 수 있습니다.

     이것은 기본적으로 가장 빠르게 사용할 수 있는 상태 머신은 아닙니다. "getting more speed" 섹션을 보면 최대의 스피드로 사용 하는 방법을 알려줍니다.

     간결하게, MSM 은 알수 없습니다. 당신이 어떤 기능을 사용하는지에 대해서 정확하게 말할 그것을 가지고 있어도


     상태 오브젝트들은 상태 머신에 자동적으로 생성됩니다. 그것들은 상태 머신이 소멸되기 전까지 존재합니다. MSM 은 boost.fusion 내부에서 사용합니다.

     이것은 당신이 상태를 10개이상 정의하게 되면 불행하게 되는것을 의미합니다. 당신은 기본에서 확장이 필요할것 입니다.

#define FUSION_MAX_VECTOR_SIZE 20 // or whatever you need


     예기치 않은 이벤트가 발생했을대, 상태 머신의 no_transition 함수가 호출됩니다. Default로, 이 함수는 단순한 어설트가 호출됩니다. no_transition 함수의 정의 다른 방법으로 핸들링하도록 overwrite 가능합니다.

template <class Fsm,class Event> 
void no_transition(Event const& e, Fsm& ,int state){...}



Defining a submachine( 서브 머신 정의 )


     우리는 Playing 상태를 상태 머신 자신으로 만들으로써 우리의 마지막 상태 머신을 확장하길 원한다.


// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

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

namespace msm = boost::msm;
namespace mpl = boost::mpl;

namespace  // Concrete FSM implementation
{
    // events
    struct play {};
    struct end_pause {};
    struct stop {};
    struct pause {};
    struct open_close {};
    struct NextSong {};
    struct PreviousSong {};

    // A "complicated" event type that carries some data.
    struct cd_detected
    {
        cd_detected(std::string name)
            : name(name)
        {}

        std::string name;
    };

    // front-end: define the FSM structure 
    struct player_ : public msm::front::state_machine_def<player_>
    {
        template <class Event,class FSM>
        void on_entry(Event const& ,FSM&) {std::cout << "entering: Player" << std::endl;}
        template <class Event,class FSM>
        void on_exit(Event const&,FSM& ) {std::cout << "leaving: Player" << std::endl;}

        // The list of FSM states
        struct Empty : public msm::front::state<> 
        {
            // every (optional) entry/exit methods get the event passed.
            template <class Event,class FSM>
            void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
            template <class Event,class FSM>
            void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
        };
        struct Open : public msm::front::state<> 
        { 
            template <class Event,class FSM>
            void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
            template <class Event,class FSM>
            void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
        };

        struct Stopped : public msm::front::state<> 
        { 
            // when stopped, the CD is loaded
            template <class Event,class FSM>
            void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
            template <class Event,class FSM>
            void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
        };

        // the player state machine contains a state which is himself a state machine
        // as you see, no need to declare it anywhere so Playing can be developed separately
        // by another team in another module. For simplicity I just declare it inside player
        struct Playing_ : public msm::front::state_machine_def<Playing_>
        {
            // when playing, the CD is loaded and we are in either pause or playing (duh)
            template <class Event,class FSM>
            void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
            template <class Event,class FSM>
            void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}

            // The list of FSM states
            struct Song1 : public msm::front::state<>
            {
                template <class Event,class FSM>
                void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
                template <class Event,class FSM>
                void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}

            };
            struct Song2 : public msm::front::state<>
            { 
                template <class Event,class FSM>
                void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
                template <class Event,class FSM>
                void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
            };
            struct Song3 : public msm::front::state<>
            { 
                template <class Event,class FSM>
                void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
                template <class Event,class FSM>
                void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
            };
            // the initial state. Must be defined
            typedef Song1 initial_state;
            // transition actions
            void start_next_song(NextSong const&)       { std::cout << "Playing::start_next_song\n"; }
            void start_prev_song(PreviousSong const&)       { std::cout << "Playing::start_prev_song\n"; }
            // guard conditions

            typedef Playing_ pl; // makes transition table cleaner
            // Transition table for Playing
            struct transition_table : mpl::vector4<
                //      Start     Event         Next      Action               Guard
                //    +---------+-------------+---------+---------------------+----------------------+
                a_row < Song1   , NextSong    , Song2   , &pl::start_next_song                       >,
                a_row < Song2   , PreviousSong, Song1   , &pl::start_prev_song                       >,
                a_row < Song2   , NextSong    , Song3   , &pl::start_next_song                       >,
                a_row < Song3   , PreviousSong, Song2   , &pl::start_prev_song                       >
                //    +---------+-------------+---------+---------------------+----------------------+
            > {};
            // Replaces the default no-transition response.
            template <class FSM,class Event>
            void no_transition(Event const& e, FSM&,int state)
            {
                std::cout << "no transition from state " << state
                    << " on event " << typeid(e).name() << std::endl;
            }
        };
        // back-end
        typedef msm::back::state_machine<Playing_> Playing;


        // state not defining any entry or exit
        struct Paused : public msm::front::state<>
        {
        };

        // the initial state of the player SM. Must be defined
        typedef Empty initial_state;

        // transition actions
        void start_playback(play const&)       { std::cout << "player::start_playback\n"; }
        void open_drawer(open_close const&)    { std::cout << "player::open_drawer\n"; }
        void close_drawer(open_close const&)   { std::cout << "player::close_drawer\n"; }
        void store_cd_info(cd_detected const& cd) {std::cout << "player::store_cd_info\n";}
        void stop_playback(stop const&)        { std::cout << "player::stop_playback\n"; }
        void pause_playback(pause const&)      { std::cout << "player::pause_playback\n"; }
        void resume_playback(end_pause const&)      { std::cout << "player::resume_playback\n"; }
        void stop_and_open(open_close const&)  { std::cout << "player::stop_and_open\n"; }
        void stopped_again(stop const&){std::cout << "player::stopped_again\n";}
        // guard conditions

        typedef player_ p; // makes transition table cleaner

        // Transition table for player
        struct transition_table : mpl::vector<
            //      Start     Event         Next      Action               Guard
            //    +---------+-------------+---------+---------------------+----------------------+
            a_row < Stopped , play        , Playing , &p::start_playback                         >,
            a_row < Stopped , open_close  , Open    , &p::open_drawer                            >,
            a_row < Stopped , stop        , Stopped , &p::stopped_again                          >,
            //    +---------+-------------+---------+---------------------+----------------------+
            a_row < Open    , open_close  , Empty   , &p::close_drawer                         >,
            //    +---------+-------------+---------+---------------------+----------------------+
            a_row < Empty   , open_close  , Open    , &p::open_drawer                          >,
            a_row < Empty   , cd_detected , Stopped , &p::store_cd_info                        >,
            //    +---------+-------------+---------+---------------------+----------------------+
            a_row < Playing , stop        , Stopped , &p::stop_playback                        >,
            a_row < Playing , pause       , Paused  , &p::pause_playback                       >,
            a_row < Playing , open_close  , Open    , &p::stop_and_open                        >,
            //    +---------+-------------+---------+---------------------+----------------------+
            a_row < Paused  , end_pause   , Playing , &p::resume_playback                      >,
            a_row < Paused  , stop        , Stopped , &p::stop_playback                        >,
            a_row < Paused  , open_close  , Open    , &p::stop_and_open                        >
            //    +---------+-------------+---------+---------------------+----------------------+
        > {};

        // Replaces the default no-transition response.
        template <class FSM,class Event>
        void no_transition(Event const& e, FSM&,int state)
        {
            std::cout << "no transition from state " << state
                << " on event " << typeid(e).name() << std::endl;
        }

    };
    // Pick a back-end
    typedef msm::back::state_machine<player_> player;

    //
    // Testing utilities.
    //
    static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };

    void pstate(player const& p)
    {
        std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
    }

    void test()
    {
        player p;
        // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
        p.start(); 
        // go to Open, call on_exit on Empty, then action, then on_entry on Open
        p.process_event(open_close()); pstate(p);
        p.process_event(open_close()); pstate(p);
        p.process_event(cd_detected("louie, louie"));
        p.process_event(play());

        // at this point, Play is active 
        // make transition happen inside it. Player has no idea about this event but it's ok.
        p.process_event(NextSong());pstate(p); //2nd song active
        p.process_event(NextSong());pstate(p);//3rd song active
        p.process_event(PreviousSong());pstate(p);//2nd song active

        p.process_event(pause()); pstate(p);
        // go back to Playing
        // as you see, it starts back from the original state
        p.process_event(end_pause());  pstate(p);
        p.process_event(pause()); pstate(p);
        p.process_event(stop());  pstate(p);
        // event leading to the same state
        p.process_event(stop());  pstate(p);
        // stop the fsm (call on_exit's, including the submachines)
        p.process_event(play());
        std::cout << "stop fsm" << std::endl;
        p.stop();
        std::cout << "restart fsm" << std::endl;
        p.start();
    }
}

int main()
{
    test();
    return 0;
}


     서브머신의 실제로 상태 머신 그자체이다. 그래서 우리는 Playing 을 front-end 와 back-end로 선택해서 정의한다.

struct Playing_ : public msm::front::state_machine_def<Playing_>{...} 
typedef msm::back::state_machine<Playing_> Playing;


     
     어떠한 상태 머신과 같이, 전이 테이블과 초기화 상태가 하나 또 필요하다.

 
struct transition_table : mpl::vector<
//    Start    Event    Target    Action                      Guard 
//   +--------+---------+--------+---------------------------+------+ 
a_row< Song1  , NextSong, Song2  , &Playing_::start_next_song        >,
a_row< Song2  , NextSong, Song1  , &Playing_::start_prev_song        >,
a_row< Song2  , NextSong, Song3  , &Playing_::start_next_song        >,
a_row< Song3  , NextSong, Song2  , &Playing_::start_prev_song        >
//   +--------+---------+--------+---------------------------+------+ 
> {};
            
typedef Song1 initial_state; 


     이것은 당신이 할 일의 모든것이다. MSM 은 Playing을 서브 상태 머신처럼 자동으로 인식하고 모든 이벤트를 Playing이 활성화되었을때 자동으로 Playing 으로 전달하여 처리한다.

     설명된 모든 상태 머신의 특색은 나중에도 유용하다. 당신은 상태 머신을 때때로 서브머신처럼 쓰거나 독립된 상태 머신처럼 사용할 수 있다.

     상태머신의 서브상태는 특정 이벤트 property 요구하는 하나의 entry action을 가진다. 컴파일러는 이 property를 지원하는 서브상태의 입장에 모든 이벤트가 들어가도록 요구한다.

     boost::enable_if / boost::disable_if 를 사용해서 예제를 작성
// define a property for use with enable_if ( enable_if를 사용하기 위해 property를 정의함 )
BOOST_MPL_HAS_XXX_TRAIT_DEF(some_event_property)

// this event supports some_event_property and a corresponding required method( some_event_property 와 호출된 함수에 맞게 지원가능한 이벤트 )
struct event1
{
   // the property
   typedef int some_event_property;
   // the method required by this property
   void some_property(){...}
};
// this event does not supports some_event_property( some_event_property를 지원하지 않는 이벤트 )
struct event2
{
};
struct some_state : public msm::front::state<>
{
   template <class Event,class Fsm>
   // enable this version for events supporting some_event_property( 활성화된 이 버젼은 some_event_property를 지원하는 이벤트를 위해 작성  )
   typename boost::enable_if<typename has_some_event_property<Event>::type,void>::type
   on_entry(Event const& evt,Fsm& fsm)
   {
      evt.some_property();
   }
   // for events not supporting some_event_property( some_event_property를 지원하지 않는 이벤트를 위해 )
   template <class Event,class Fsm>
   typename boost::disable_if<typename has_some_event_property<Event>::type,void>::type
   on_entry(Event const& ,Fsm& )
   {    }
};          



Orthogonal regions, terminate state, event defferring

     그것은 많은 스테이트 머신이 가지는 처리 오류에 매우 공통적인 문제점 이다. 그것은 보통 모든 스테이트가 가지는 특별한 오류 상태로부터 정의된 전이를 포함한다.

     그것은 또한 상태의 오류를 따르는것을 찾는데 실용적이지 않다. 아래의 매우 가독성이 명확하지 않는 예제를 보자


      





     이것은 가독성이 좋지도 아름답지도 않다.

     우리는 여전히 가독성이 안좋게 만드는 전이의 어떠한 액션도 심지어 가질 수 없다(?)

     운좋게도, UML은 도움이 되는 컨셉을 제공한다. orthogonal regions. 

     그것들을 보아라. 경량화된 상태 머신이 구동되는 같은 시간에 내부에 공통 상태 머신 그리고 하나의 다른 영향을 미치는 능력을 가진 상태를

     효과는 당신이 아무때나 가진 몇개의 활성화된 상태이다. 우리는 그렇게 유지할 수 잇다. 우리의 상태 머신을 이전 예제와 단지 새로운 구역을 두개의 상태로 정의함으로써, allok, errormode.

     allok는 대부분 활성화 되어있다(?). 그러나 error_found error event는 두번째 구역을 만드다 새롭게 활성화된 상태 error 모드로 이동하는

     이 이벤트는 main region에 그것이 간단하게 무시하게되어 흥미롭지 않다 . "no_transition"은 호출될것 이다 모든 이벤트 처리를 하는 구역이 없으면

     또한 UML의 의무 처럼, 모든 구역은 이벤트를 처리할 기회를 가집니다. 명령안에 initial_state type에 의해 정의된것처럼

     orthogonal region 추가는 쉽습니다. 하나 유일하게 initial_state 타입 정의에서 스테이트를 좀 더 추가하는 것이 정의가 필요합니다.

     region의 initial state와 같이 Allok 새로운 구역을 추가합니다.

typedef mpl::vector<Empty,AllOk> initial_state;


      



     구역 1, 2가 생겼다.

     게다가, 당신이 에러를 찾을때, 당신은 보통 처리된 진행된(?) 된 이벤트를 원하지 않습니다. 이것을 달성하기 위해, 우리는 다른 UML 기능, terminate state를 사용합니다.

     어떤 구역이 terminate state로 이동할 때, state machine "terminates" 와 모든 이벤트들은 무시됩니다. 이것은 물론 필수적은 아닙니다.

     하나는 terminate states가 없는 orthogonal regions를 사용 할 수 있습니다. MSM은 또 UML, interrupt states의 작은 연장을 제공합니다.

     그래서 그것은 terminate state, 당신이 조건이 만족했을 때 되돌리기를 허용했던 다른 상태 머신과 와 같습니다

     
     이 예제는 이벤트 지연 처리를 여기에 보여준다. 어떤 사람이 disc를 밀어 넣고 당장 플레이 버튼을 누르는 것을 말해보자. 그 이벤트는 처리할 수 없다. 

     여전히 당신은 그것이 뒤늦은 시점에 처리되기를 유저가 강제로 플레이를 누르지 않도록 되기를 원한다.

     해결책은 Empty 또는 Open상태에서 지연된것 처럼 정의되는 것이다. 그리고 이벤트가 지연되지 않았던 첫번째 상태에서 처리된 될 수 있는것

     그것은 처리되거나 거부 될 수 있다. 이 예제에서, 정지가 활성화 되었을 때, 이벤트는 처리된다 왜냐하면 유일한 Empty와 Open 은 이벤트가 지연되었기 때문에

     
     UML은 이벤트 지연을 state property 처럼 정의 한다. MSM 당신이 이것을 제공된 지연이벤트 타입으로 작성하게 한다.


struct Empty : public msm::front::state<> 
{
   // if the play event is fired while in this state, defer it until a state( 이 상태 안에서 플레이 이벤트를 발생시키면, 그 이벤트는 상태가 처리되거나 그것을 거부할때까지 지연된다. )
   // handles or rejects it
   typedef mpl::vector<play> deferred_events;
...
};        


     예제를 보자
// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

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

namespace msm = boost::msm;
namespace mpl = boost::mpl;

namespace
{
    // events
    struct play {};
    struct end_pause {};
    struct stop {};
    struct pause {};
    struct open_close {};
    struct NextSong {};
    struct PreviousSong {};
    struct error_found {};
    struct end_error {};
    struct end_error2 {};

    // Flags. Allow information about a property of the current state
    struct PlayingPaused{};
    struct CDLoaded {};
    struct FirstSongPlaying {};

    // A "complicated" event type that carries some data.
    struct cd_detected
    {
        cd_detected(std::string name)
            : name(name)
        {}

        std::string name;
    };

    // front-end: define the FSM structure 
    struct player_ : public msm::front::state_machine_def<player_>
    {
        template <class Event,class FSM>
        void on_entry(Event const& ,FSM&) 
        {
            std::cout << "entering: Player" << std::endl;
        }
        template <class Event,class FSM>
        void on_exit(Event const&,FSM& ) 
        {
            std::cout << "leaving: Player" << std::endl;
        }
        // The list of FSM states
        struct Empty : public msm::front::state<> 
        {
            // if the play event arrives in this state, defer it until a state handles it or
            // rejects it
            typedef mpl::vector<play> deferred_events;
            // every (optional) entry/exit methods get the event passed.
            template <class Event,class FSM>
            void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
            template <class Event,class FSM>
            void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
        };
        struct Open : public msm::front::state<> 
        { 
            // if the play event arrives in this state, defer it until a state handles it or
            // rejects it
            typedef mpl::vector<play> deferred_events;
            typedef mpl::vector1<CDLoaded>      flag_list;
            template <class Event,class FSM>
            void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
            template <class Event,class FSM>
            void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
        };

        struct Stopped : public msm::front::state<> 
        { 
            // when stopped, the CD is loaded
            typedef mpl::vector1<CDLoaded>      flag_list;
            template <class Event,class FSM>
            void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
            template <class Event,class FSM>
            void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
        };

        // the player state machine contains a state which is himself a state machine
        // as you see, no need to declare it anywhere so Playing can be developed separately
        // by another team in another module. For simplicity I just declare it inside player
        struct Playing_ : public msm::front::state_machine_def<Playing_>
        {
            // when playing, the CD is loaded and we are in either pause or playing (duh)
            typedef mpl::vector2<PlayingPaused,CDLoaded>        flag_list;

            template <class Event,class FSM>
            void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
            template <class Event,class FSM>
            void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
            // The list of FSM states
            struct Song1 : public msm::front::state<>
            {
                typedef mpl::vector1<FirstSongPlaying>      flag_list;
                template <class Event,class FSM>
                void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
                template <class Event,class FSM>
                void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
            };
            struct Song2 : public msm::front::state<>
            { 
                template <class Event,class FSM>
                void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
                template <class Event,class FSM>
                void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
            };
            struct Song3 : public msm::front::state<>
            { 
                template <class Event,class FSM>
                void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
                template <class Event,class FSM>
                void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
            };
            // the initial state. Must be defined
            typedef Song1 initial_state;
            // transition actions
            void start_next_song(NextSong const&)       { std::cout << "Playing::start_next_song\n"; }
            void start_prev_song(PreviousSong const&)       { std::cout << "Playing::start_prev_song\n"; }
            // guard conditions

            typedef Playing_ pl; // makes transition table cleaner
            // Transition table for Playing
            struct transition_table : mpl::vector4<
                //      Start     Event         Next      Action               Guard
                //    +---------+-------------+---------+---------------------+----------------------+
                a_row < Song1   , NextSong    , Song2   , &pl::start_next_song                       >,
                a_row < Song2   , PreviousSong, Song1   , &pl::start_prev_song                       >,
                a_row < Song2   , NextSong    , Song3   , &pl::start_next_song                       >,
                a_row < Song3   , PreviousSong, Song2   , &pl::start_prev_song                       >
                //    +---------+-------------+---------+---------------------+----------------------+
            > {};
            // Replaces the default no-transition response.
            template <class FSM,class Event>
            void no_transition(Event const& e, FSM&,int state)
            {
                std::cout << "no transition from state " << state
                    << " on event " << typeid(e).name() << std::endl;
            }
        };
        // back-end
        typedef msm::back::state_machine<Playing_> Playing;

        // state not defining any entry or exit
        struct Paused : public msm::front::state<>
        {
            typedef mpl::vector2<PlayingPaused,CDLoaded>        flag_list;
        };
        struct AllOk : public msm::front::state<>
        {
            template <class Event,class FSM>
            void on_entry(Event const&,FSM& ) {std::cout << "starting: AllOk" << std::endl;}
            template <class Event,class FSM>
            void on_exit(Event const&,FSM& ) {std::cout << "finishing: AllOk" << std::endl;}
        };
        // this state is also made terminal so that all the events are blocked
        struct ErrorMode :  //public msm::front::terminate_state<> // ErrorMode terminates the state machine
            public msm::front::interrupt_state<end_error/*mpl::vector<end_error,end_error2>*/ >   // ErroMode just interrupts. Will resume if
                                                            // the event end_error is generated
        {
            template <class Event,class FSM>
            void on_entry(Event const&,FSM& ) {std::cout << "starting: ErrorMode" << std::endl;}
            template <class Event,class FSM>
            void on_exit(Event const&,FSM& ) {std::cout << "finishing: ErrorMode" << std::endl;}
        };
        // the initial state of the player SM. Must be defined
        typedef mpl::vector<Empty,AllOk> initial_state;

        // transition actions
        void start_playback(play const&)       { std::cout << "player::start_playback\n"; }
        void open_drawer(open_close const&)    { std::cout << "player::open_drawer\n"; }
        void close_drawer(open_close const&)   { std::cout << "player::close_drawer\n"; }
        void store_cd_info(cd_detected const& cd) {std::cout << "player::store_cd_info\n";}
        void stop_playback(stop const&)        { std::cout << "player::stop_playback\n"; }
        void pause_playback(pause const&)      { std::cout << "player::pause_playback\n"; }
        void resume_playback(end_pause const&)      { std::cout << "player::resume_playback\n"; }
        void stop_and_open(open_close const&)  { std::cout << "player::stop_and_open\n"; }
        void stopped_again(stop const&){std::cout << "player::stopped_again\n";}
        void report_error(error_found const&) {std::cout << "player::report_error\n";}
        void report_end_error(end_error const&) {std::cout << "player::report_end_error\n";}

        // guard conditions
 
        typedef player_ p; // makes transition table cleaner

        // Transition table for player
        struct transition_table : mpl::vector<
            //      Start     Event         Next      Action               Guard
            //    +---------+-------------+---------+---------------------+----------------------+
            a_row < Stopped , play        , Playing , &p::start_playback                         >,
            a_row < Stopped , open_close  , Open    , &p::open_drawer                            >,
            a_row < Stopped , stop        , Stopped , &p::stopped_again                          >,
            //    +---------+-------------+---------+---------------------+----------------------+
            a_row < Open    , open_close  , Empty   , &p::close_drawer                           >,
            //    +---------+-------------+---------+---------------------+----------------------+
            a_row < Empty   , open_close  , Open    , &p::open_drawer                            >,
            a_row < Empty   , cd_detected , Stopped , &p::store_cd_info                          >,
            //    +---------+-------------+---------+---------------------+----------------------+
            a_row < Playing , stop        , Stopped , &p::stop_playback                          >,
            a_row < Playing , pause       , Paused  , &p::pause_playback                         >,
            a_row < Playing , open_close  , Open    , &p::stop_and_open                          >,
            //    +---------+-------------+---------+---------------------+----------------------+
            a_row < Paused  , end_pause   , Playing , &p::resume_playback                        >,
            a_row < Paused  , stop        , Stopped , &p::stop_playback                          >,
            a_row < Paused  , open_close  , Open    , &p::stop_and_open                          >,
            //    +---------+-------------+---------+---------------------+----------------------+
            a_row < AllOk   , error_found ,ErrorMode, &p::report_error                           >,
            a_row <ErrorMode,end_error    ,AllOk    , &p::report_end_error                       >
            //    +---------+-------------+---------+---------------------+----------------------+
        > {};

        // Replaces the default no-transition response.
        template <class FSM,class Event>
        void no_transition(Event const& e, FSM&,int state)
        {
            std::cout << "no transition from state " << state
                << " on event " << typeid(e).name() << std::endl;
        }
    };
    // Pick a back-end
    typedef msm::back::state_machine<player_> player;

    //
    // Testing utilities.
    //
    static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused","AllOk","ErrorMode" };

    void pstate(player const& p)
    {
        // we have now several active states, which we show
        for (unsigned int i=0;i<player::nr_regions::value;++i)
        {
            std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
        }
    }

    void test()
    {
        player p;
        // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
        p.start(); 
        // test deferred event
        // deferred in Empty and Open, will be handled only after event cd_detected
        p.process_event(play());

        // tests some flags
        std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl; //=> false (no CD yet)
        // go to Open, call on_exit on Empty, then action, then on_entry on Open
        p.process_event(open_close()); pstate(p);
        p.process_event(open_close()); pstate(p);
        p.process_event(cd_detected("louie, louie"));

        // at this point, Play is active (was deferred)
        std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
        std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> true

        // make transition happen inside it. Player has no idea about this event but it's ok.
        p.process_event(NextSong());pstate(p); //2nd song active
        p.process_event(NextSong());pstate(p);//3rd song active
        p.process_event(PreviousSong());pstate(p);//2nd song active
        std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false

        std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
        p.process_event(pause()); pstate(p);
        std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
        // go back to Playing
        // as you see, it starts back from the original state
        p.process_event(end_pause());  pstate(p);
        p.process_event(pause()); pstate(p);
        p.process_event(stop());  pstate(p);
        std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> false
        std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl;//=> true
        // by default, the flags are OR'ed but you can also use AND. Then the flag must be present in 
        // all of the active states
        std::cout << "CDLoaded active with AND:" << std::boolalpha << p.is_flag_active<CDLoaded,player::Flag_AND>() << std::endl;//=> false

        // event leading to the same state
        p.process_event(stop());  pstate(p);

        // event leading to a terminal/interrupt state
        p.process_event(error_found());  pstate(p);
        // try generating more events
        std::cout << "Trying to generate another event" << std::endl; // will not work, fsm is terminated or interrupted
        p.process_event(play());pstate(p);
        std::cout << "Trying to end the error" << std::endl; // will work only if ErrorMode is interrupt state
        p.process_event(end_error());pstate(p);
        std::cout << "Trying to generate another event" << std::endl; // will work only if ErrorMode is interrupt state
        p.process_event(play());pstate(p);
        std::cout << "stop fsm" << std::endl;
        p.stop();

    }
}

int main()
{
    test();
    return 0;
}

     이것은 UML 그리고 간단하게 수집되는 동안, 그것은 하나는 지연되길 원했던 어떤 조건 때문에 항상 실용적이진 않다?

     하나는 또 만들기를 원할 수 있었던 전이 행동 부분이 된 이 파츠 추가되었던 좀더 복잡한 행동의 가드의 보너스


'Boost' 카테고리의 다른 글

Boost Assign 샘플  (0) 2016.01.29
Boost Array 샘플  (0) 2016.01.29
Boost Any 샘플  (0) 2016.01.29
boost::mpl 라이브러리를 이용한 Packet의 자동 생성 및 처리 방법  (0) 2014.05.26
boost - MPL 정리 중  (0) 2014.04.22
      Boost  |  2014. 4. 22. 16:44



홍쿤사마's Blog is powered by Daum