在C ++ 11中编译可自定义状态机(具有子状态支持)的时间错误检查

时间:2015-10-16 14:00:07

标签: c++11 state variadic-templates

我正在使用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;
}

1 个答案:

答案 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);