|
Boost Users : |
From: Felipe Magno de Almeida (felipe.m.almeida_at_[hidden])
Date: 2008-06-24 00:37:53
On Mon, Jun 23, 2008 at 6:18 PM, Andreas Huber
<ahd6974-spamboostorgtrap_at_[hidden]> wrote:
> "Felipe Magno de Almeida" <felipe.m.almeida_at_[hidden]> wrote in message
> news:a2b17b60806211502i447c22e1t9d552dd76b8972a1_at_mail.gmail.com...
[snip]
>> IIUC the diagram, the functional factory solution allows both Y and Z
>> to have arguments to its
>> constructors.
>> The Y state could pass the arguments to its base with the arguments
>> for Z constructor, which
>> would then create a factory to instantiate Z.
>
> So you're suggesting that simple_state::simple_state() should be overloaded
> say 10 times, one templated overload for each distinct number of parameters?
Yes. This can be done very easily with boost.preprocessor.
#ifndef BOOST_STATECHART_PARAMS
#define BOOST_STATECHART_PARAMS 10
#endif
#define BOOST_STATECHART_DETAIL_generate_overload(z, n, data) \
template <BOOST_PP_ENUM_PARAMS(n, typename A)> \
simple_state(BOOST_PP_ENUM_BINARY_PARAMS(n, A, a)) \
: boost::bind(boost::factory<InitialState*>(), BOOST_PP_ENUM_PARAMS(n, a)) \
{}
BOOST_PP_REPEAT(SMTP_CLIENT_DETAIL_PARAMS,
BOOST_STATECHART_DETAIL_generate_overload, ~)
#undef BOOST_STATECHART_DETAIL_generate_overload
Something like that, but taking care of the 0 version which is not
handled above.
If you find it too inconvenient, a simple fusion sequence works too.
In my cppgui library I use a fusion sequence to allow passing argument
constructors
to windows:
wnd<my_window> w = create<my_window>( _arguments =
fusion::make_vector(a1, a2, a3) );
But since this lib uses boost.named_parameters, I can't pass multiple
arguments to it,
so a sequence is the only thing that fits. Maybe as syntactic sugar
this could be done,
instead of overloading simple_state constructor.
template <typename T0>
fusion::vector<T0> inner_state_arguments(T0);
template <typename T0, typename T1>
fusion::vector<T0, T1> inner_state_arguments(T0 a0, T1 a1);
We could write:
struct Z : sc::simple_state<Y, Z>
{
Z(int, int);
};
struct Y : sc::simple_state<Y, X, Z>
{
Y() : sc::simple_state(inner_state_arguments(0,1))
{}
};
And then simple_state could use a fusion sequence to create a factory.
This transfers the overload to something else, but at least the intent
it is more explicit.
>> If someone wants to pass arguments to X, then they should transit to
>> X, and X transit to Y IMHO.
>
> Transiting to X could be semantically different from transiting to Y. In the
> diagram discussed so far it's not but looking at the transitions triggered
> by e3 and e4 in ...
>
> http://i.cmpnet.com/embedded/gifs/9901/9901feat1fig4.gif
>
> ... you'll see an example where it is. Transiting to S0 leads to the entry
> of S0 and S0_1 while transiting to S0_2 leads to the entry of S0 and S0_2.
I understand. But if someone is trying to transit directly to an
inner state, does he care about the local-state of the new outer state?
This is not rhetorical actually, I'm a little inexperienced with
developing state machines.
So far I've writed a SMTP client with asio, and am creating a SMTP server.
I have no other experience with state machines.
>> I see your triggering_event idea, and I find it not very useful
>> because of its necessary downcast
>> and dynamic typing, it also seems to me that the reponsability to
>> receive the arguments continue
>> to be in the just-entered state. Which I find dissatisfying.
>
> I wholeheartedly agree, but apart from your factory suggestion I've not yet
> seen any good ideas how this could be improved.
I hope I convince you of my idea then. :)
> Even if we were to go the
> factory route (my version), you'd be forced to implement quite a few factory
> classes (I guess approximately one for each state ctor with parameters).
I don't think creating classes is a good idea. The constructors would still
be fixed.
I believe constructor overloading is of much importance in this. A simple
construction indirection is all that's needed for this to work.
[snip]
> You could make your events visitable, in which case you could do with a
> finite number of casts/virtual function calls for any number of state ctors.
> Of course, this would require the implementation of a visitor class, which
> isn't exactly elegant either.
I believe I'd rather continue with the workaround I use today.
sc::result react( event1 const& )
{
state_machine& m = context<state_machine>();
sc::result r = transit<new_state>();
new_state const& s = m.state_cast<new_state const&>();
s.initialize(a1, a2);
return r;
}
Even with the many pitfalls this has (everyday I forget to copy
local-state I need to pass along to a automatic variable before
calling transt<>) it is at least more straightforward.
> Regards,
>
> --
> Andreas Huber
Regards,
-- Felipe Magno de Almeida
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