2015-10-16 18 views
1

我正在設計使用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; 
} 
+0

你是否僅僅爲了教育目的而這麼做? [boost :: msm]怎麼樣(http://www.boost.org/doc/libs/1_59_0/libs/msm/doc/HTML/index.html)? –

+0

部分用於教育目的,即學習利用C++ 11中的新特性 - 我以前使用boost狀態圖編寫了一個FSM,並且它最終很難讀取... – allsey87

+0

boost狀態圖和增強meta狀態機分別是兩個不同的庫,不知道你使用哪一個 –

回答

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::tupleclass... SUBSTATES繼承。那麼,如果我可以寫下如下內容:

cStateMachine.AddTransition(EState::COUNT_FOO, EState::COUNT_BAR);