Boost State Machine Language - 来自 `action` 的 `post` 事件
Boost State Machine Language - `post` event from within an `action`
我已经使用 boost sml 几天了,我已经到了需要 post/从动作中处理事件的地步。
我可以看到它可以直接从转换 table:
完成
using namespace sml;
return make_transition_table(
*"s1"_s + event<my_event> / process_event(other_event{}) = "s2"_s,
"s2"_s + event<other_event> = X
);
但我的用例不同:
我有一个状态有一个 action
for on-entry
事件,它做了一些工作,并最终触发了一个事件(来自 within
状态 action
)。
例如,使用 boost statechart
,每个州都可以访问 context
,并且可以 post_event
。
sml
可以吗?
有可能。你需要做两件事。
一种是将 boost::sml::queue
模板参数设置为 boost::sml::sm
.
// sml::process_queue is for post event
sml::sm<table, sml::process_queue<std::queue>> sm;
发布的事件需要被推入队列。当当前转换完成时,事件从队列中弹出并处理。为此,Boost.SML 需要一些队列。 sml::process_queue<std::queue>
提供队列类型。您可以传递满足队列概念的任何类型,其行为类似于 std::queue
.
另一种是将sml::back::process<comma_separated_list_of_processed_event_types>
参数设置为动作处理程序,如下所示:
[](auto const& /*ev*/, sml::back::process<other_event /*, my_event*/ > process) {
参数进程是可调用的。因此,您可以将 process
作为函数调用。当您调用 process(event)
时,事件将发布到队列中。
这是一个示例代码:
#include <iostream>
#include <queue>
#include <boost/sml.hpp>
int main() {
namespace sml = boost::sml;
struct my_event {};
struct other_event {};
struct table {
auto operator()() const noexcept {
using namespace sml;
return make_transition_table(
*"s1"_s + event<my_event> /
// In order to post event in the action,
// you need to define the action handler as follows.
// The key is the second parameter.
// `sml::back::process` is posting event callable type.
// You need to pass all event types that are posted in the action handler
// as the template argument.
// Unfortunately you cannot write `sml::back::process<_>` for all events.
[](auto const& /*ev*/, sml::back::process<other_event /*, my_event*/ > process) {
std::cout << "before post" << std::endl;
process(other_event{});
std::cout << "after post" << std::endl;
} = "s2"_s,
"s2"_s + event<other_event> = X,
// entry exit log
"s1"_s + sml::on_entry<_> / [] { std::cout << "s1 on entry" << std::endl; },
"s1"_s + sml::on_exit<_> / [] { std::cout << "s1 on exit" << std::endl; },
"s2"_s + sml::on_entry<_> / [] { std::cout << "s2 on entry" << std::endl; },
"s2"_s + sml::on_exit<_> / [] { std::cout << "s2 on exit" << std::endl; }
);
};
};
// sml::process_queue is for post event
sml::sm<table, sml::process_queue<std::queue>> sm;
sm.process_event(my_event{});
}
我已经使用 boost sml 几天了,我已经到了需要 post/从动作中处理事件的地步。
我可以看到它可以直接从转换 table:
using namespace sml;
return make_transition_table(
*"s1"_s + event<my_event> / process_event(other_event{}) = "s2"_s,
"s2"_s + event<other_event> = X
);
但我的用例不同:
我有一个状态有一个 action
for on-entry
事件,它做了一些工作,并最终触发了一个事件(来自 within
状态 action
)。
例如,使用 boost statechart
,每个州都可以访问 context
,并且可以 post_event
。
sml
可以吗?
有可能。你需要做两件事。
一种是将 boost::sml::queue
模板参数设置为 boost::sml::sm
.
// sml::process_queue is for post event
sml::sm<table, sml::process_queue<std::queue>> sm;
发布的事件需要被推入队列。当当前转换完成时,事件从队列中弹出并处理。为此,Boost.SML 需要一些队列。 sml::process_queue<std::queue>
提供队列类型。您可以传递满足队列概念的任何类型,其行为类似于 std::queue
.
另一种是将sml::back::process<comma_separated_list_of_processed_event_types>
参数设置为动作处理程序,如下所示:
[](auto const& /*ev*/, sml::back::process<other_event /*, my_event*/ > process) {
参数进程是可调用的。因此,您可以将 process
作为函数调用。当您调用 process(event)
时,事件将发布到队列中。
这是一个示例代码:
#include <iostream>
#include <queue>
#include <boost/sml.hpp>
int main() {
namespace sml = boost::sml;
struct my_event {};
struct other_event {};
struct table {
auto operator()() const noexcept {
using namespace sml;
return make_transition_table(
*"s1"_s + event<my_event> /
// In order to post event in the action,
// you need to define the action handler as follows.
// The key is the second parameter.
// `sml::back::process` is posting event callable type.
// You need to pass all event types that are posted in the action handler
// as the template argument.
// Unfortunately you cannot write `sml::back::process<_>` for all events.
[](auto const& /*ev*/, sml::back::process<other_event /*, my_event*/ > process) {
std::cout << "before post" << std::endl;
process(other_event{});
std::cout << "after post" << std::endl;
} = "s2"_s,
"s2"_s + event<other_event> = X,
// entry exit log
"s1"_s + sml::on_entry<_> / [] { std::cout << "s1 on entry" << std::endl; },
"s1"_s + sml::on_exit<_> / [] { std::cout << "s1 on exit" << std::endl; },
"s2"_s + sml::on_entry<_> / [] { std::cout << "s2 on entry" << std::endl; },
"s2"_s + sml::on_exit<_> / [] { std::cout << "s2 on exit" << std::endl; }
);
};
};
// sml::process_queue is for post event
sml::sm<table, sml::process_queue<std::queue>> sm;
sm.process_event(my_event{});
}