如何将数据传递到 boost::sml 状态机内的事件以使用“直接”处理方法?

问题描述 投票:0回答:2

考虑 sml 文档中有关进程和延迟的示例, 我重写了一点,以将依赖项传递给状态机以在事件处理中使用:


// $CXX -std=c++14 defer_and_process.cpp
#include <boost/sml.hpp>
#include <cassert>
#include <deque>
#include <queue>

namespace sml = boost::sml;

namespace {
struct e1 {};
struct e2 {int dependency = 0;};
struct e3 {};
struct e4 {};

struct defer_and_process {
  auto operator()() const noexcept {
    using namespace sml;
    return make_transition_table(
       *"idle"_s + event<e1> / defer
      , "idle"_s + event<e2> = "s1"_s
      , "s1"_s   + event<e1> / process(e2{/*pass my_dependency here*/}) = "s2"_s // this is the interesting bit
      , "s2"_s   + event<e3> / process(e4{})
      , "s2"_s   + event<e4> = X
    );
  }
};
}  // namespace

int main() {
  int my_dependency = 42;
  using namespace sml;
  sm<defer_and_process, sml::defer_queue<std::deque>, sml::process_queue<std::queue>>
      sm{my_dependency}; 
  assert(sm.is("idle"_s));

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

  assert(!sm.process_event(e2{}));  /// triggers idle -> s1 and s1 -> s2 (via deferred e1)
  assert(sm.is("s2"_s));

  assert(sm.process_event(e3{}));  /// triggers s2.process(e4) -> X (via processed e4)
  assert(sm.is(sml::X));
}

是否可以直接这样做,或者...

Boost 状态机语言中描述的 lambda 方式 - 来自“action”中的“post”事件

唯一的方法吗?内联不可能吗?

喜欢

process(e2{some way to pull the data out of the sm dependency list and pass it here })

c++ boost state-machine boost-sml
2个回答
0
投票

放入静态依赖项已经可以正常工作了。如果它需要是动态的,那么(显然?)需要可调用对象方法,因为没有其他方法可以访问上下文:

// $CXX -std=c++14 defer_and_process.cpp
#include <boost/sml.hpp>
#include <cassert>
#include <deque>
#include <functional>
#include <iostream>
#include <queue>

namespace sml = boost::sml;

namespace {
    struct e1 {};
    struct e2 { int dependency = 0; };
    struct e3 {};
    struct e4 {};

    struct injectable {
        int dependency;
    };

    struct defer_and_process {
        auto operator()() const noexcept {
            using namespace sml;

            auto action = [](injectable& i, sml::back::process<e2> process) {
                std::cout << "posting with e2{" << i.dependency << "}" << std::endl;
                process(e2{i.dependency});
            };

            return make_transition_table(             //
                *"idle"_s + event<e1> / defer,        //
                "idle"_s + event<e2>        = "s1"_s, //
                "s1"_s + event<e1> / action = "s2"_s, //
                "s2"_s + event<e3> / process(e4{}),   //
                "s2"_s + event<e4> = X                //
            );
        }
    };
} // namespace

int main() {
    for (auto dep : {0, 42, -314}) {
        using namespace sml;
        sm<                                //
            defer_and_process,             //
            sml::defer_queue<std::deque>,  //
            sml::process_queue<std::queue> //
        > sm{injectable{dep}};

        assert(sm.is("idle"_s));

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

        assert(!sm.process_event(e2{})); /// triggers idle -> s1 and s1 -> s2 (via deferred e1)
        assert(sm.is("s2"_s));

        assert(sm.process_event(e3{})); /// triggers s2.process(e4) -> X (via processed e4)
        assert(sm.is(sml::X));
    }
}

请注意,您可以使用一些语法糖隐藏该可调用对象。例如:

#include <boost/core/demangle.hpp>
#include <boost/sml.hpp>
#include <cassert>
#include <deque>
#include <functional>
#include <iostream>
#include <queue>

namespace sml = boost::sml;

namespace {
    struct injectable {
        int dependency = 0;
    };

    struct e1 {};
    struct e2 {
        int dependency;
        e2(injectable const& i = {}) : dependency(i.dependency) {}
    };
    struct e3 {};
    struct e4 {
        int dependency;
        e4(injectable const& i = {}) : dependency(i.dependency) {}
    };

    template <typename E> struct inj_process {
        void operator()(injectable& i, sml::back::process<E> process) const {
            std::cout << "posting with " << boost::core::demangle(typeid(E).name()) << "{" << i.dependency
                      << "}" << std::endl;
            process(E{i});
        };
    };

    struct defer_and_process {
        auto operator()() const noexcept {
            using namespace sml;

            return make_transition_table(                        //
                *"idle"_s + event<e1> / defer,                   //
                "idle"_s + event<e2>                   = "s1"_s, //
                "s1"_s + event<e1> / inj_process<e2>{} = "s2"_s, //
                "s2"_s + event<e3> / inj_process<e4>{},          //
                "s2"_s + event<e4> = X                           //
            );
        }
    };
} // namespace

int main() {
    for (auto dep : {0, 42, -314}) {
        using namespace sml;
        sm<                                //
            defer_and_process,             //
            sml::defer_queue<std::deque>,  //
            sml::process_queue<std::queue> //
        > sm{injectable{dep}};

        assert(sm.is("idle"_s));

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

        assert(!sm.process_event(e2{})); /// triggers idle -> s1 and s1 -> s2 (via deferred e1)
        assert(sm.is("s2"_s));

        assert(sm.process_event(e3{})); /// triggers s2.process(e4) -> X (via processed e4)
        assert(sm.is(sml::X));
    }
}

印刷

posting with (anonymous namespace)::e2{0}
posting with (anonymous namespace)::e4{0}
posting with (anonymous namespace)::e2{42}
posting with (anonymous namespace)::e4{42}
posting with (anonymous namespace)::e2{-314}
posting with (anonymous namespace)::e4{-314}

0
投票

显然可调用对象是正确的选择。明白了。

© www.soinside.com 2019 - 2024. All rights reserved.