考虑 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 })
?
放入静态依赖项已经可以正常工作了。如果它需要是动态的,那么(显然?)需要可调用对象方法,因为没有其他方法可以访问上下文:
// $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}
显然可调用对象是正确的选择。明白了。