Boost State Machine Language - `post` событие из` action` - PullRequest
0 голосов
/ 23 октября 2019

Я использую boost sml в течение нескольких дней, и я дошел до того, что мне нужно опубликовать / обработать и событие из действия. Я вижу, что это можно сделать непосредственно из таблицы переходов:

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 для on-entry, которое выполняет некоторую работу и, в конце концов, вызывает событие (из within состояние action).

Например, с помощью boost statechart, каждый штат имел доступ к context и мог post_event.

Возможно ли это с sml?

1 Ответ

2 голосов
/ 24 октября 2019

Это возможно. Вам нужно сделать 2 вещи. Одним из них является установка 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{});
}

Демонстрационная версия: https://wandbox.org/permlink/yueELv7SoFbPCEW1

...