[Boost::ext].SML: доступ к SM и зависимостям в действии

#c #boost #c 14 #state-machine #boost-extension

#c #boost #c 14 #конечный автомат #boost-расширение

Вопрос:

Я использую SML (https://boost-ext.github.io/sml /) v.1.1.3 и мне нужно получить доступ к введенным зависимостям и конечному автомату в действиях. В соответствии со следующим коммитом это уже должно работать: https://github.com/boost-ext/sml/commit/e6d0685993a8a0160dde1610d7f8be4f811c89d0 Этот коммит был результатом этой проблемы: https://github.com/boost-ext/sml/issues/94

В последующем примере, когда я пытаюсь получить доступ к зависимостям и sm в action2, я получаю ошибку компиляции:

 sml.hpp:1853:18: note:   cannot convert ‘deps’ (type ‘boost::ext::sml::v1_1_3::aux::pool<int, {anonymous}::actions_guardsamp;, {anonymous}::actions_guards>’) to type ‘intamp;’  1853 |     return object(event, sm, deps, subs);
  

Пример:

 #include <boost/sml.hpp>
#include <cassert>
#include <iostream>

namespace sml = boost::sml;

namespace {
 
struct e1 {};
struct e2 {};
struct e3 {};

auto action2 = [](const autoamp; event, autoamp; sm, intamp; i, std::stringamp; str) {
    assert(42 == i);
    std::cout << "action2" << std::endl;
    std::cout << "sm.n: " << sm.n << std::endl;
};

struct actions_guards {
    using self = actions_guards;

    int n = 10;

    auto operator()() {
        using namespace sml;

        auto action1 = [](auto e) { std::cout << "action1: " << typeid(e).name() << std::endl; };

        auto guard1 = [](int i) {
            assert(42 == i);
            std::cout << "guard2" << std::endl;
            return false;
        };

        return make_transition_table(
            //  Start           Event             Guard                         Action                        Next
            // ------------- ------------------- --------------------------- ------------------------------- ------------------------------- 
                *"idle"_s       event<e1>       [ guard1 ]                  /   action1                     = "s1"_s,
                "s1"_s          event<e2>       [ amp;self::guard2 ]           /   action2                     = "s2"_s,
                "s2"_s          event<e3>                                                                   = X
        );
    }

    bool guard2(int i) const noexcept {
        assert(42 == i);
        std::cout << "guard3" << std::endl;
        return true;
    }
};

}  // namespace

int main( int argc, char* argv[] )
{
    actions_guards ag{};
    std::string strDep( "127.0.0.1" );
    int intDep = 42;
    sml::sm<actions_guards> sm{ag, intDep, strDep};
    sm.process_event(e1{});
    sm.process_event(e2{});
    sm.process_event(e3{});

    assert(sm.is(sml::X));

    return 0;
}
  

Ошибка:

 ...
sml.hpp:1340:10:   required from ‘bool boost::ext::sml::v1_1_3::back::sm_impl< <template-parameter-1-1> >::process_event(const TEventamp;, TDepsamp;, TSubsamp;) [with TEvent = {anonymous}::e2; TDeps = boost::ext::sml::v1_1_3::aux::pool<int, {anonymous}::actions_guardsamp;, {anonymous}::actions_guards>; TSubs = boost::ext::sml::v1_1_3::aux::pool<boost::ext::sml::v1_1_3::back::sm_impl<boost::ext::sml::v1_1_3::back::sm_policy<{anonymous}::actions_guards> > >; TSM = boost::ext::sml::v1_1_3::back::sm_policy<{anonymous}::actions_guards>]’
/usr/local/oecore-x86_64_tux_dunfell/sysroots/armv5te-angstrom-linux-gnueabi/usr/include/boost/sml.hpp:1660:81:   required from ‘bool boost::ext::sml::v1_1_3::back::sm< <template-parameter-1-1> >::process_event(const TEventamp;) [with TEvent = {anonymous}::e2; typename boost::ext::sml::v1_1_3::aux::enable_if<boost::ext::sml::v1_1_3::aux::integral_constant<bool, __is_base_of(TEvent, boost::ext::sml::v1_1_3::back::sm::events_ids)>::value, int>::type <anonymous> = 0; TSM = boost::ext::sml::v1_1_3::back::sm_policy<{anonymous}::actions_guards>]’
main.cpp:86:23:   required from here
/usr/local/oecore-x86_64_tux_dunfell/sysroots/armv5te-angstrom-linux-gnueabi/usr/include/boost/sml.hpp:1853:18: error: no match for call to ‘(boost::ext::sml::v1_1_3::aux::zero_wrapper<{anonymous}::<lambda(const auto:3amp;, auto:4amp;, intamp;, std::stringamp;)>, void>) (const {anonymous}::e2amp;, boost::ext::sml::v1_1_3::back::sm_impl<boost::ext::sml::v1_1_3::back::sm_policy<{anonymous}::actions_guards> >amp;, boost::ext::sml::v1_1_3::aux::pool<int, {anonymous}::actions_guardsamp;, {anonymous}::actions_guards>amp;, boost::ext::sml::v1_1_3::aux::pool<boost::ext::sml::v1_1_3::back::sm_impl<boost::ext::sml::v1_1_3::back::sm_policy<{anonymous}::actions_guards> > >amp;)’
 1853 |     return object(event, sm, deps, subs);
      |            ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
main.cpp:37:16: note: candidate: ‘template<class auto:3, class auto:4> {anonymous}::<lambda(const auto:3amp;, auto:4amp;, intamp;, std::stringamp;)>’
   37 | auto action2 = [](const autoamp; event, autoamp; sm, intamp; i, std::stringamp; str) {
      |                ^
main.cpp:37:16: note:   template argument deduction/substitution failed:
In file included from main.cpp:20:
/usr/local/oecore-x86_64_tux_dunfell/sysroots/armv5te-angstrom-linux-gnueabi/usr/include/boost/sml.hpp:1853:18: note:   cannot convert ‘deps’ (type ‘boost::ext::sml::v1_1_3::aux::pool<int, {anonymous}::actions_guardsamp;, {anonymous}::actions_guards>’) to type ‘intamp;’
 1853 |     return object(event, sm, deps, subs);
      |            ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
  

Ответ №1:

Ответ от автора SML в конце выпуска # 399:

Реализация этой функции была изменена, чтобы избежать рекурсивных вызовов и соответствовать UML-2.5

Пример

 s1   event<e1> / [](sml::back::process<e2, e3> processEvent) -> void {
            processEvent(e2{});
            processEvent(e3{});
          }
  

При определении sm должен быть указан process_queue

 sml::sm<c, sml::process_queue<std::queue>> sm{};
  

Полный пример

Вот адаптированный пример из моего актуального вопроса:

 #include <iostream>
#include <cassert>
#include <queue>
#include <boost/sml.hpp>

namespace sml = boost::sml;

struct e1 {};
struct e2 {};
struct e3 {};

struct my_dep {
    int val = 0;
};

auto action = [](sml::back::process<e2, e3> processEvent, my_depamp; dep) {
    if (dep.val == 0) {
        processEvent(e2{});
          dep.val;
    }
    else
        processEvent(e3{});
};

struct table {
    auto operator()() const noexcept {
        using namespace sml;
        return make_transition_table(
            *"s1"_s   event<e1> / action = "s3"_s
            ,"s1"_s   event<e2> = "s2"_s
            ,"s3"_s   event<e2> = "s4"_s
            ,"s3"_s   event<e3> = "s5"_s
            ,"s4"_s   event<e1> = "s1"_s
        );
    }
};

int main() {
    using namespace sml;
    my_dep md;
    sm<table, sml::process_queue<std::queue>> sm{md};

    sm.process_event(e1{});
    assert(sm.is("s4"_s));

    sm.process_event(e1{});
    assert(sm.is("s1"_s));

    sm.process_event(e1{});
    assert(sm.is("s5"_s));
}