[Boost::ext].SML:有没有办法存储回调以便稍后处理事件?

[Boost::ext].SML: Is there a way to store a callback to later process an event?

我来自 Boost MSM,现在正尝试使用 SML 1.1.3 实现相同的状态机。 使用 SML,我无法访问状态机本身,我不得不使用注入的依赖项。我也大量使用 D-Bus,现在我在进行异步 D-Bus 调用时遇到问题。异步 D-Bus 调用是在注入依赖项的方法中进行的。当 D-Bus 调用完成时,调用依赖项内的回调。我需要一种方法来向状态机发出事件。 存储 sml::back::process 不起作用,我无法确定在异步 D-Bus 调用完成后它是否仍然有效。

示例:

    auto queryDBusAction = []( Dep& dep, sml::back::process<Ev_Result> processEvent ) {
        dep.makeAsyncDBusCall( SomeCallback );
    };

...

class Dep
{
public:
    void makeAsyncDBusCall( SomeCallback cb )
    {
        _cb = cb;
        _client.someAsyncDBusCall( boost::bind( &Dep::dbusCallFinished, this, _1 ) );
    }

protected:
    DBusClient _client;
    SomeCallback _cb;

    void dbusCallFinished( Result& result, const DBus::Error& dbusError )
    {
        // Here I need a way/callback to emit an event
        // that gets processed by the state machine
        _cb( Ev_Result{result} );
    }
};

为了访问状态机本身,您需要将应用程序 class 分离到基础 class 和子 class。 基 class 具有纯虚成员函数声明。 您可以从 sml transition table action.

调用成员函数

您需要在转换 table 定义 后定义子 class 。 现在,sub class 可以访问转换 table 的整个定义。 这意味着 您可以包含 sml::sm 作为子 class.

的成员

所以可以从成员函数中调用sml后端的process_event()函数。参见 memfun1()

#include <iostream>
#include <cassert>

#include <boost/sml.hpp>
#include <boost/asio.hpp>

namespace sml = boost::sml;

struct e1 {};
struct e2 {};

// Separate member function declarations as the base class
struct app_base {
    virtual void memfun1() = 0;
    virtual void memfun2(int) const = 0;
    virtual ~app_base() = default;
};
    
struct app_table {
    auto operator()() const noexcept {
        using namespace sml;
        // I can write member function call in action thanks to base class app_base
        return make_transition_table(
            // source event      guard                     action                                    target
            *"s1"_s + event<e1>  [([] { return true; })] / [](app_base& appb)  { appb.memfun1(); }   = "s2"_s
            ,"s2"_s + event<e2>                          / [](app_base& appb)  { appb.memfun2(42); } = "s1"_s
        );
    }
};

struct app : app_base {
    app(boost::asio::io_context& ioc):ioc { ioc } {}
    
    // post asynchronous callback function that calls process_event()
    void memfun1() override {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
        boost::asio::post(
            ioc, 
            [this] { 
                std::cout << "async callback is called. call process_event()" << std::endl;
                sm_.process_event(e2{});

                using namespace sml;
                assert(sm_.is("s1"_s));
            }
        );
    }
    void memfun2(int v) const override {
        std::cout << __PRETTY_FUNCTION__ << ":" << v << std::endl;
    }

    // state machine backend can be a member of application class
    sml::sm<app_table> sm_ { static_cast<app_base&>(*this) };
    boost::asio::io_context& ioc;
};

int main() {
    using namespace sml;
    boost::asio::io_context ioc; // for async operation example
    
    app a { ioc };
    assert(a.sm_.is("s1"_s));
    a.sm_.process_event(e1{});
    assert(a.sm_.is("s2"_s));
    
    ioc.run(); // async loop start until async event will become empty
}

可运行演示:https://wandbox.org/permlink/9XFQAMHuRcMPeU64