Boost logo

Boost Users :

Subject: Re: [Boost-users] [msm] how to write a generic class for allstatemachine back-end.
From: Michael Caisse (boost_at_[hidden])
Date: 2011-06-27 15:10:33


On 06/27/2011 12:06 PM, Christophe Henry wrote:
>> 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

FWIW ... this is basically what I do also. It works nicely.

-- 
Michael Caisse
Object Modeling Designs
www.objectmodelingdesigns.com

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