我正在使用C ++ 11设计通用状态机。由于使用std::string
来识别状态,我只能在运行时捕获错误。我想在编译时指定代码中的状态时更改此选项以捕获错误。
我一直在玩基于可变参数模板和枚举类的几个想法,但还没有找到解决方案,至少没有一个相当干净/可读的解决方案。
我当前状态机的一些代码段位于下面,其中包含完整的可运行代码:http://cpp.sh/26njm
SState sStateChart("fsm", {
SState("init", {
SState("init_foo"),
SState("init_bar"),
}),
SState("count", {
SState("count_foo"),
SState("count_bar"),
}),
SState("display", {
SState("display_foo"),
SState("display_bar"),
}),
});
SState
的构造函数获取状态ID的std::string
,然后通过子状态的初始化列表初始化std::vector<SState>
,如下所示:
struct SState {
SState(const std::string& str_id,
const std::vector<SState>& vec_sub_states = {}) :
Id(str_id),
SubStates(vec_sub_states) {
}
//...
std::string Id;
std::vector<SState> SubStates;
//...
};
然后可以使用以下语法进一步定义状态图表:
方法
std::function<void()> fnInitFoo = [&] {
std::cerr << "fnInitFoo" << std::endl;
foo = 0;
};
sStateChart["init"]["init_foo"].SetEntryFunction(fnInitFoo);
转换
std::function<bool()> fnTransInitFooInitBar = [&] {
return (bar != 0);
};
sStateChart["init"].AddTransition("init_foo","init_bar", fnTransDisplayToInit);
为了感兴趣,这就是我正在研究的基于可变参数模板的状态层次结构。我暂时放弃了这个想法,因为它变得复杂而没有显示任何解决我的问题的迹象 - 我想我可以以某种方式将枚举类作为参数之一传递给模板,但它没有比我的例子更好使用字符串......
template<class... SUBSTATES> class CState {};
template<class STATE, class... SUBSTATES>
class CState<STATE, SUBSTATES...> : private CState<SUBSTATES...> {
};
enum class ETopLevelStates {INIT, COUNT, DISPLAY};
enum class EInitStates {INIT_FOO, INIT_BAR};
int main() {
CState<
CState<
CState<>,
CState<>
>,
CState<>,
CState<>
> cStateMachine;
return 0;
}
答案 0 :(得分:0)
这编译并可能成为有趣事物的起点:
/* States */
enum class EState : unsigned int {
FSM,
INIT, INIT_FOO, INIT_BAR,
COUNT, COUNT_FOO, COUNT_BAR,
DISPLAY, DISPLAY_FOO, DISPLAY_BAR
};
template<EState STATE, class... SUBSTATES> class CState {};
int main() {
CState<EState::FSM,
CState<EState::INIT,
CState<EState::INIT_FOO>,
CState<EState::INIT_BAR>
>,
CState<EState::COUNT,
CState<EState::COUNT_FOO>,
CState<EState::COUNT_BAR>
>,
CState<EState::DISPLAY,
CState<EState::DISPLAY_FOO>,
CState<EState::DISPLAY_BAR>
>
> cStateMachine;
return 0;
}
我想我可以在std::tuple
继续进行,并从class... SUBSTATES
继承。如果我能按照以下方式写一些内容,那将会是多么好的呢?
cStateMachine.AddTransition(EState::COUNT_FOO, EState::COUNT_BAR);