在C++ 11中,我可以引用在模板参数中定义的枚举类

sto*_*tic 4 c++ enums templates c++11

这是我试图编写的代码的简化版本:

template<typename Derived>
class StateMachine
{
public:
  void SetState(Derived::State s) {
    static_cast<Derived*>(this)->TransitionTo(s);
  }
};

class MyFSM : public StateMachine<MyFSM>
{
public:
  enum class State {
    State1,
    State2,
    State3
  };
  void TransitionTo(State s) {
    _state = s;
  }
private:
  State _state = State::State1;  
};
Run Code Online (Sandbox Code Playgroud)

我正在使用带有clang的c ++ 11.我在这里得到的错误是10:17: error: missing 'typename' prior to dependent type name 'Derived::State'声明SetState.我也试过添加typename Derived::State DerivedState;然后使用DerivedState而不是Derived::State,但后来我得到了error: unknown type name 'DerivedState'.

更令人困惑的是,我试过typedef typename Derived::State DerivedState;,然后我得到了错误:error: no type named 'State' in 'MyFSM'.我的最后一次尝试是typedef enum class Derived::State DerivedState;,然后我得到了最令人困惑的错误:error: no enum named 'State' in 'MyFSM'.

我在这里深入了解模板,欢迎任何帮助理解这一点!此外,这里可能有更好的模式.我要做的主要是这个StateMachine类有一些共同的功能,然后有一堆不同的状态机,每个状态机都有自己的状态和转换功能.我这样做,需要传递的另一种方式thisSetState(从内调用时MyFSM,这是我在做什么的简化版本),但是这是丑陋的人,它自己的原因.我很想避免这种有层次性的课程,但我的主要目标是使派生类尽可能易于编写和理解.

小智 5

您可以通过制作SetState模板来延迟类型扣除:

#include <type_traits>

template<typename Derived>
class StateMachine
{
public:
  template <typename State>
  void SetState(State s) {
    static_assert(std::is_same<State, typename Derived::State>::value, "Not a derived state");
    static_cast<Derived*>(this)->TransitionTo(s);
  }
};

class MyFSM : public StateMachine<MyFSM>
{
public:
  enum class State {
    State1,
    State2,
    State3
  };
  void TransitionTo(State s) {
    _state = s;
  }
private:
  State _state = State::State1;
};

int main() {
    MyFSM fsm;
    fsm.SetState(MyFSM::State::State1);
    // error: static assertion failed: Not a derived state
    // fsm.SetState(0);
}
Run Code Online (Sandbox Code Playgroud)