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

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;
};

我正在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类具有一些通用功能,然后有许多不同的状态机,每个状态机都有自己的状态和转换功能。我有另一种方法,需要将this传递给SetState(当从MyFSM中调用时,这是我正在做的简化版本),但这是丑陋的,这是由于其自身的原因。我很想避免这种受诱惑的类,但是我的主要目标是使派生类尽可能容易编写和理解。

最佳答案

您可以通过将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);
}

09-28 11:30