我使用 boost::sml
设计了这个状态机struct LooperStateMachine {
auto operator()() const {
using namespace sml;
return make_transition_table(
*"beggining"_s + event<heel> / onRecordFirstLoop.value() = "recording_first_loop"_s,
"recording_first_loop"_s + event<heel>[is_heel_valid] / onRecordLoops.value() = "recording_other_loops_and_playing"_s,
"recording_first_loop"_s + event<toe>[is_toe_valid] / onPlayLoops.value() = "playing_loops"_s,
"playing_loops"_s + event<toe>[is_toe_valid]/onStopPlayingLoops.value() = "stopped"_s,
"playing_loops"_s + event<heel>[is_heel_valid]/onRecordLoops.value() = "recording_other_loops_and_playing"_s,
"recording_other_loops_and_playing"_s + event<toe>[is_toe_valid] / onPlayLoops.value() = "playing_loops"_s,
"stopped"_s + event<toe>[is_toe_valid] / onClearLoops.value() = "beggining"_s,
"stopped"_s + event<heel>[is_heel_valid] / onSaveLoops.value() = "stopped"_s
);
}
std::optional<std::function<void()>> onClearLoops;
std::optional<std::function<void()>> onSaveLoops;
std::optional<std::function<void()>> onPlayLoops;
std::optional<std::function<void()>> onRecordLoops;
std::optional<std::function<void()>> onRecordFirstLoop;
std::optional<std::function<void()>> onStopPlayingLoops;
};
但是,要使用它,
sm
自动实例化它:
int main() {
using namespace sml;
sm<LooperStateMachine> sm;
所以我没有机会设置我的功能。
如何设置功能?
对于你的literal问题,你可能只提供一个默认的构造函数/NSMI。不过,我知道您希望能够“动态”切换这些操作“挂钩”。
关于注入函数钩子,文档say:
SML 状态不能有数据,因为数据被直接注入到守卫/动作中
这给了我将 runtime 状态与状态机分离的想法:
旁白:可选函数是多余的,
已经可以是无值的,并且可以方便地转换为 bool fdr,就像function<>
一样。optional<>
#include <boost/sml.hpp>
#include <functional>
#include <iostream>
namespace sml = boost::sml;
namespace looping {
struct heel { };
struct toe { };
static auto is_heel_valid = []() { return false; };
static auto is_toe_valid = []() { return false; };
using DynamicAction = std::function<void()>;
struct Hooks {
DynamicAction onClearLoops;
DynamicAction onSaveLoops;
DynamicAction onPlayLoops;
DynamicAction onRecordLoops;
DynamicAction onRecordFirstLoop;
DynamicAction onStopPlayingLoops;
};
static auto onClearLoops = [](Hooks &hooks) { if (hooks.onClearLoops) hooks.onClearLoops(); };
static auto onSaveLoops = [](Hooks &hooks) { if (hooks.onSaveLoops) hooks.onSaveLoops(); };
static auto onPlayLoops = [](Hooks &hooks) { if (hooks.onPlayLoops) hooks.onPlayLoops(); };
static auto onRecordLoops = [](Hooks &hooks) { if (hooks.onRecordLoops) hooks.onRecordLoops(); };
static auto onRecordFirstLoop = [](Hooks &hooks) { if (hooks.onRecordFirstLoop) hooks.onRecordFirstLoop(); };
static auto onStopPlayingLoops = [](Hooks &hooks) { if (hooks.onStopPlayingLoops) hooks.onStopPlayingLoops(); };
struct LooperStateMachine {
auto operator()() const {
using namespace sml;
return make_transition_table(
*"beginning"_s + event<heel> / onRecordFirstLoop = "recording_first_loop"_s,
"recording_first_loop"_s + event<heel>[is_heel_valid] / onRecordLoops = "recording_other_loops_and_playing"_s,
"recording_first_loop"_s + event<toe>[is_toe_valid] / onPlayLoops = "playing_loops"_s,
"playing_loops"_s + event<toe>[is_toe_valid]/onStopPlayingLoops = "stopped"_s,
"playing_loops"_s + event<heel>[is_heel_valid]/onRecordLoops = "recording_other_loops_and_playing"_s,
"recording_other_loops_and_playing"_s + event<toe>[is_toe_valid] / onPlayLoops = "playing_loops"_s,
"stopped"_s + event<toe>[is_toe_valid] / onClearLoops = "beginning"_s,
"stopped"_s + event<heel>[is_heel_valid] / onSaveLoops = "stopped"_s
);
}
};
}
int main() {
looping::Hooks hooks;
hooks.onClearLoops = [] { std::cout << "Clearing them\n"; };
sml::sm<looping::LooperStateMachine> sm(hooks);
}
免责声明:我对这个库只有最薄弱的了解。我发现它是一个令人费解的东西,但以一种越来越积极的方式来处理。