sml
sml copied to clipboard
Can't declare state on forward declared submachine
I tried to hide the state machine implementation behind an interface and pimpl. It all works well for a simple state machine, but not for one with submachine.
MNWE (minimal not working example):
namespace sml = boost::sml;
// hpp
struct e1 {};
struct e2 {};
struct inner;
const auto idle = sml::state<class idle>;
const auto idle2 = sml::state<class idle2>;
const auto s1 = sml::state<class s1>;
const auto state_inner = sml::state<inner>;
// cpp
struct inner {
auto operator()() const noexcept {
using namespace sml;
return make_transition_table(
*idle + event<e1> = s1
);
}
};
struct outer {
auto operator()() const noexcept {
using namespace sml;
return make_transition_table(
*idle2 + event<e2> = state_inner
);
}
};
int main() {
sml::sm<outer, sml::testing> sm;
assert(sm.is(idle2));
sm.set_current_states(state_inner);
sm.set_current_states<decltype(state_inner)>(s1);
assert(sm.is(state_inner));
assert(sm.is<decltype(state_inner)>(s1));
}
This fails to compile, because when state_inner
is created, struct inner
is only forward-declared and it's not known if it's callable.
If this was checked at sml::sm
instantiation, I think it should work.
#99 might be related.
What prevents you from writing the following?
struct outer {
auto operator()() const noexcept {
using namespace sml;
return make_transition_table(
*idle2 + event<e2> = state<inner>
);
}
};
It doesn't fix the problem. If in my example I replace every state_inner
with sml::state<inner>
, but leave the forward declaration of state_inner
, the code still won't compile.
What am I missing? The following works fine for me:
namespace sml = boost::sml;
// hpp
struct e1 {};
struct e2 {};
struct inner;
struct idle{};
struct idle2{};
struct s1{};
// cpp
struct inner {
auto operator()() const noexcept {
using namespace sml;
return make_transition_table(
*sml::state<idle> + event<e1> = sml::state<s1>
);
}
};
struct outer {
auto operator()() const noexcept {
using namespace sml;
return make_transition_table(
*sml::state<idle2> + event<e2> = sml::state<inner>
);
}
};
int main() {
sml::sm<outer, sml::testing> sm;
assert(sm.is(sml::state<idle2>));
sm.set_current_states(sml::state<inner>);
sm.set_current_states<decltype(sml::state<inner>)>(sml::state<s1>);
assert(sm.is(sml::state<inner>));
assert(sm.is<decltype(sml::state<inner>)>(sml::state<s1>));
return 0;
}