C++
boost
boost.msm

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

More than 1 year has passed since last update.

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