LoginSignup
6
6

More than 5 years have passed since last update.

Boost.MSMと包含を利用してprivate空間にアクセス可能なクラス内有限状態マシンを実装する

Last updated at Posted at 2016-10-25

Boost.MSMをPimplイディオムと組み合わせることで、外部に隠蔽しつつ、privateな空間にもアクセス可能なクラス内有限状態マシンを実装する。
ヘッダファイルにBoost.MSMを使用している痕跡を残さずに、有限状態マシン内で基本オブジェクト(ここではFooオブジェクト)に自由にアクセスすることができる。

Foo.h
#pragma once

#include <memory>

struct Foo
{
    Foo();
    ~Foo();

    void changeState();
private:
    struct Impl;
    std::unique_ptr<Impl> pImpl;
};
Foo.cpp
#include <iostream>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/back/state_machine.hpp>

struct Foo::Impl
{
// *** ポイント1
// Implクラスのクラス内クラスとしてBoost.MSM用クラスを定義する

    // 状態の定義
    struct RunState : boost::msm::front::state<>{

        // Fooクラスのprivate変数にアクセスしている。
        template<typename Event, typename FSM>
        void on_entry(Event event, FSM fsm)
        {
            std::cout << "Run  : " << ++(fsm.base->pImpl->value) << std::endl;
//          std::cout << "Run  : " << ++(value) << std::endl;   // Foo::Impl::valueには直接アクセスできない
        }
    };
    struct StopState : boost::msm::front::state<>{
        template<typename Event, typename FSM>
        void on_entry(Event event, FSM fsm)
        {
            std::cout << "Stop : " << ++(fsm.base->pImpl->value) << std::endl;
        }
    };

    // イベントの定義
    struct ChangeEvent {};

    // 有限状態マシンの定義
    struct Machine_ : boost::msm::front::state_machine_def<Machine_>
    {
        // 状態遷移テーブル
        struct transition_table : boost::mpl::vector
            < _row< RunState, ChangeEvent, StopState >
            , _row< StopState, ChangeEvent, RunState >
            > {};

        // 初期状態
        using initial_state = StopState;

// *** ポイント2
// 有限状態マシンの定義内で基本オブジェクト(Fooクラスのオブジェクト)を保持する

        // 基本オブジェクトのポインタを保持。ここから基本オブジェクトにアクセスする
        Foo*const base;

        // 有限状態マシンのコンストラクタ
        Machine_(Foo*const obj) : base(obj){}
    };

    // 有限状態マシンクラスの定義
    using Machine = boost::msm::back::state_machine< Machine_ >;
    Machine machine; // 有限状態マシンをImplクラス内で保持する(包含)

    Impl(Foo*const obj)
        : machine(obj)
        , value(0)
    {
    }

    // プライベート変数
    int value;
};

Foo::Foo()
    :pImpl(new Foo::Impl(this))
{
    pImpl->machine.start();
}

Foo::~Foo()
{}

void Foo::changeState()
{
    pImpl->machine.process_event(Impl::ChangeEvent());
}
main.cpp
#include "Foo.h"

int main()
{
    Foo foo;
    foo.changeState();
    foo.changeState();

    return 0;
}
result
Stop : 1
Run  : 2
Stop : 3
6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6