Boost logo

Boost Users :

Subject: Re: [Boost-users] [msm] how to write a generic class for all statemachine back-end.
From: Juraj Ivanèiæ (juraj.ivancic_at_[hidden])
Date: 2011-06-27 08:36:10


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_ ) );
     }
};

HTH


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