Boost logo

Boost Users :

Subject: Re: [Boost-users] [msm] how to write a generic class for allstatemachine back-end.
From: Christophe Henry (christophe.j.henry_at_[hidden])
Date: 2011-06-27 15:06:37


> On 23.6.2011. 22:04, Christophe Henry wrote:
>> >In our project, we need a generic interface to refer to different
>> state machine (back-end). For example, in the following codes, we want
>>
>> >to use SMBase* to refer to any concrete state machine. SMBase should
>> have similar interface as state machine.
>>
>> >struct User {
>> > A(SMBase* s) : sm(s) ();
>> > SMBase* sm;
>> > ...
>> > // User can use sm->start(), sm->process_event() etc
>> >}
>>
>> >struct SMBase
>> >{
>> > virtual void start() = 0;
>> > ... // how to design the rest ???
>> >}
>>
>> >The problem of designing SMBase is the function "process_event". We
>> want it to to be virtual function so SMWrapper can implement it. >But it
>> also needs to be a template according to state machine interface. But we
>> cannot have a virtual template function.
>>
>> >How can we achieve/design this generic state machine interface?
>>
>> Hi Jerry,
>>
>> Yes, virtual template methods are not possible in C++ :(
>>
>> (Note to C++ Standard Comittee: I'd consider donating a kidney for this
>> one :) )
>>
>> This leaves you with few possibilies. I see 2 at a first glance
>> (suggestions welcome):
>>
>> - virtual void process_event_event1(); virtual void
>> process_event_event2(); ...etc (not fun but quite in the OO spirit)
>>
>> - virtual void process_event(boost::any) followed by any_casts until you
>> find the correct one (not fun either)
>>
>> All considered, solution 1 looks better. If you can define a common
>> interface for state machines, then they are bound to expect common
>> events.
>
> I have a combination of the above two which is quite fun :)
> Use boost.variant on all event types:
>
> typedef boost::variant<ev1, ev2, ev3> event_variant
>
> virtual void process_event( event_variant e ) = 0
>
> and to use its apply_visitor function in derived class to force MSM to
> instantiate all needed process_event templates (untested):
>
> template<typename SM>
> struct ProcessEvent
> {
> ProcessEvent( SM & sm ) : sm_( sm ) {}
> template<typename event>
> void operator( event & e )
> {
> sm_.process_event( e );
> }
>
> SM & sm_;
> };
>
> template <typename SM>
> class SMWrapper : public SMBase
> {
> virtual void process_event( event_variant ev )
> {
> boost::variant::apply_visitor( ev,
> ProcessEvent<SM>( sm_ ) );
> }
> };

Ah yes I didn't think about this solution, it's clearly more elegant. I need
to give it a try. Good one :)

Thanks,

Christophe


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net