这里有一个 boost sml C++ 库的 hello world 示例:https://boost-ext.github.io/sml/examples.html#hello-world
// $CXX -std=c++14 hello_world.cpp
#include <boost/sml.hpp>
#include <cassert>
namespace sml = boost::sml;
namespace {
struct release {};
struct ack {};
struct fin {};
struct timeout {};
const auto is_ack_valid = [](const ack&) { return true; };
const auto is_fin_valid = [](const fin&) { return true; };
const auto send_fin = [] {};
const auto send_ack = [] {};
#if !defined(_MSC_VER)
struct hello_world {
auto operator()() const {
using namespace sml;
return make_transition_table(
*"established"_s + event<release> / send_fin = "fin wait 1"_s,
"fin wait 1"_s + event<ack> [ is_ack_valid ] = "fin wait 2"_s,
"fin wait 2"_s + event<fin> [ is_fin_valid ] / send_ack = "timed wait"_s,
"timed wait"_s + event<timeout> / send_ack = X
);
}
};
}
int main() {
using namespace sml;
sm<hello_world> sm;
static_assert(1 == sizeof(sm), "sizeof(sm) != 1b");
assert(sm.is("established"_s));
sm.process_event(release{});
assert(sm.is("fin wait 1"_s));
sm.process_event(ack{});
assert(sm.is("fin wait 2"_s));
sm.process_event(fin{});
assert(sm.is("timed wait"_s));
sm.process_event(timeout{});
assert(sm.is(X)); // released
}
#else
class established;
class fin_wait_1;
class fin_wait_2;
class timed_wait;
struct hello_world {
auto operator()() const {
using namespace sml;
return make_transition_table(
*state<established> + event<release> / send_fin = state<fin_wait_1>,
state<fin_wait_1> + event<ack> [ is_ack_valid ] = state<fin_wait_2>,
state<fin_wait_2> + event<fin> [ is_fin_valid ] / send_ack = state<timed_wait>,
state<timed_wait> + event<timeout> / send_ack = X
);
}
};
}
int main() {
using namespace sml;
sm<hello_world> sm;
assert(sm.is(state<established>));
sm.process_event(release{});
assert(sm.is(state<fin_wait_1>));
sm.process_event(ack{});
assert(sm.is(state<fin_wait_2>));
sm.process_event(fin{});
assert(sm.is(state<timed_wait>));
sm.process_event(timeout{});
assert(sm.is(X)); // released
}
#endif
我理解
_s
创建一个带有名称的状态,并且状态上可以发生事件,这会将状态机发送到另一个状态。
让我们看看
hello_world
状态机:
struct hello_world {
auto operator()() const {
using namespace sml;
return make_transition_table(
*"established"_s + event<release> / send_fin = "fin wait 1"_s,
"fin wait 1"_s + event<ack> [ is_ack_valid ] = "fin wait 2"_s,
"fin wait 2"_s + event<fin> [ is_fin_valid ] / send_ack = "timed wait"_s,
"timed wait"_s + event<timeout> / send_ack = X
);
}
};
如果我理解正确的话,这意味着当状态机处于状态
established
并且接收到事件release
时,它会进入状态fin wait 1
。 send_fin
是什么? *
中的 *state<established> + event<release> / send_fin = state<fin_wait_1>
是什么?这个疯狂的语法是什么?我认为 +
、/
和 =
只是被覆盖的运算符,可以轻松创建转换表。另外,is_ack_valid
是什么?
我对
*
的猜测是它指定了状态机的开始状态。
事件是发生的事情。
如果我理解正确的话,这意味着当状态机处于 状态建立并收到事件释放,它进入状态 等待 1.
正确
send_fin 是什么?
在已建立的状态下收到释放时触发的操作。它是一个在示例中完全不执行任何操作的 lambda。 :耸肩:
*state + event / send_fin = 中的*是什么 state
这个疯狂的语法是什么?我认为+、/和= 只是被覆盖的运算符,可以轻松创建 转换表。
*是初始状态,你是对的。值得注意的是,复杂的转换表实际上可以跟踪多个子机器,因此每个部分有多个 * 。
我非常怀疑你是对的,运算符重载稍微驱动了语法。说到设计,它还通过 TMP 对编译时间进行了大量优化。
另外,is_ack_valid 是什么?
事件后用方括号括起来的表达式称为守卫。即使收到事件,评估为 false 的守卫也会阻止任何操作或转换的发生。
在这个简单的例子中,lambda 总是返回 true,所以它是没有用的。一个更完整的示例实际上会检查确认上的某些内容。
我对*的猜测是它指定了状态的开始状态 机器。
正确
事件是发生的事情。
当然。它们毫无价值,它们是强类型的,并有意调度到状态机。
以下未经请求的评论。
我现在在工作中大量使用 SML。起初,这是另一件事需要学习,因为我已经在用消防水龙带喝水了。
使用了一段时间后,我想说的积极的事情是它可以非常简洁地表示复杂的流程控制,而且非常高效。
如果您有机会观看 Kris 的 2019 年 c++ now 演讲,他的 TCP 连接状态管理就是一个很好的例子,说明了这一点。