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

Boost.statechart でイベントを受け取る。

C++

 Boost.statechart でイベントに応じて何かするプログラムを実装してみます。通った車の台数を数えるカウンタです。

 カウンタは go_through_car イベントを受け取ると車の台数をインクリメントします。但しこのカウンタは enable, disable の 2 状態を持ち、disable のときにはカウントしません。toggle_enable_disable イベントで enable/disable が切り替わります。

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

namespace sc = boost::statechart;


namespace states
{
	struct enable;
	struct disable;
};

// 状態マシンの定義
class car_counter : public sc::state_machine< car_counter, states::disable >
{
public:
	car_counter() : count_( 0 ) { initiate(); }
	int & count()               { return count_; }
	int const & count() const   { return count_; }
private:
	int count_;
};

// イベントの定義
namespace events
{
	struct toggle_enable_disable : sc::event< toggle_enable_disable > {};
	struct go_through_car        : sc::event< go_through_car >   {};
}

// 状態の定義
namespace states
{
	struct disable : sc::simple_state< disable, car_counter >
	{
		typedef sc::transition<
			events::toggle_enable_disable, enable
		> reactions;
	};
	
	struct enable  : sc::simple_state<  enable, car_counter >
	{
		typedef boost::mpl::list<
			sc::transition< events::toggle_enable_disable, disable >,
			sc::custom_reaction< events::go_through_car > 
		> reactions;
		
		sc::result react( events::go_through_car const & e )
		{
			++ context< car_counter >().count();
			return discard_event();
		}
		
	};
}

解説は後回しにして使ってみます。

#include <iostream>

int main()
{
	// disable 状態で初期化
	car_counter cc;
	
	for( int i = 0; i < 50; ++ i ) {
		switch( i ) {
		// 20 ~ 24 の間は disable 
		case 0: case 20: case 25: case 50:
			cc.process_event( events::toggle_enable_disable() );
			// no break;
		default:
			cc.process_event( events::go_through_car() );
			break;
		}
	}
	
	std::cout << sw.count() << std::endl;
}

結果

45

 面白いのは reactions の定義ですね。disable では、transition ひとつだけで定義してます。一方 enable では、 複数の挙動を mpl::list を使って表現しています。

 Boost::statechart では reactions が肝ですねはい。

 mpl::list 部分の詳細は、読んでみれば分かりますが、
・toggle_enable_disable イベントを受け取ったら disable へ遷移する。
・go_through_car イベントを受け取ったときは custom_reaction する。
 と書いてあります。それぞれのイベントにどう反応するのかをここでまとめて記述するわけです。


この custom_reaction がもう一つのポイントになります。

 react メンバ関数を定義してやることで、動的に状態遷移を指定できます。この例では discard_event() を return してますが、これは "状態遷移しない" ということです。transit< T > を return すると状態 T に遷移できます。
 また context メンバ関数で car_counter にアクセスしています。ここでインクリメントしてるわけですね。

※ 英語のセンスねーな