我正在設計使用C++ 11的一般狀態機。由於使用std::string
來識別狀態,我可以只在運行時捕獲錯誤。我想在編譯時在代碼中指定狀態時將其更改爲捕獲錯誤。在C++中編譯時間錯誤檢查一個可自定義的狀態機(與子狀態支持)11
我一直在玩基於variadic模板和枚舉類的幾個想法,但還沒有找到一個解決方案,至少沒有一個是合理的乾淨/可讀。
我目前的狀態機的一些片段是下面的完整運行的代碼爲: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
構造函數採用std::string
爲國家ID,然後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;
}
你是否僅僅爲了教育目的而這麼做? [boost :: msm]怎麼樣(http://www.boost.org/doc/libs/1_59_0/libs/msm/doc/HTML/index.html)? –
部分用於教育目的,即學習利用C++ 11中的新特性 - 我以前使用boost狀態圖編寫了一個FSM,並且它最終很難讀取... – allsey87
boost狀態圖和增強meta狀態機分別是兩個不同的庫,不知道你使用哪一個 –