c++ 简单有限状态机模板

klsxnrf1  于 2023-06-25  发布在  其他
关注(0)|答案(1)|浏览(190)

我正在尝试一个非常简单的FSM,在入口和出口处都有动作。流行的(?)示例传递原始指针并使用手动资源管理(例如https://refactoring.guru/design-patterns/state/cpp/example
我的目标是使用自动化的资源管理和简单的界面。所以我尝试使用模板。它的工作和界面是OK-ish

  1. class Fsm;
  2. class State {
  3. public:
  4. virtual ~State() = default;
  5. void SetFsm(Fsm* fsm) { fsm_ = fsm; }
  6. virtual void Enter() = 0;
  7. virtual void Exit() = 0;
  8. protected:
  9. // to allow state changes
  10. Fsm* fsm_{ nullptr };
  11. };
  12. class Fsm {
  13. public:
  14. template <class T>
  15. void TransitionTo() {
  16. if (state_ != nullptr) {
  17. // if switching to same state, do nothing
  18. const auto temp = std::make_unique<T>();
  19. if (dynamic_cast<T*>(state_.get()) != nullptr) { return; }
  20. state_->Exit();
  21. }
  22. state_ = std::make_unique<T>();
  23. state_->SetFsm(this);
  24. state_->Enter();
  25. }
  26. private:
  27. std::unique_ptr<State> state_;
  28. };

在定义了class MyState1class MyState2之后,可以将其称为

  1. const auto my_object = std::make_unique<Fsm>();
  2. my_object->TransitionTo<MyState1>();
  3. my_object->TransitionTo<MyState2>()

但它不允许在构造时传递状态,因为模板化的构造函数不是一个东西。所以我创建了这个构造函数

  1. Fsm(std::unique_ptr<State> state = nullptr) : state_(std::move(state)) {}

但结果就是

  1. const auto my_object = std::make_unique<Fsm>(std::make_unique<MyState1>());

有什么建议如何使它成为一个更简单的构造函数吗?关于使用模板完成这项任务,有什么一般性的说明吗?

hfwmuf9z

hfwmuf9z1#

如果接口和可读性是您唯一关心的问题,并且您想摆脱编写长行的嵌套函数,那么您可以简单地实现工厂模式。
例如:

  1. class Fsm
  2. {
  3. public:
  4. class factory
  5. {
  6. public:
  7. template <typename T, typename... Args>
  8. static std::unique_ptr<Fsm> create(Args&&... args)
  9. {
  10. auto fsm_ptr = new Fsm(std::make_unique<T>( std::forward<Args>(args)... ));
  11. return std::unique_ptr<Fsm>( fsm_ptr );
  12. }
  13. };
  14. // DONT FORGET FRIEND CLASS
  15. friend class factory;
  16. // MAKE CONSTRUCTOR PRIVATE
  17. private:
  18. Fsm(std::unique_ptr<State> state = nullptr) : state_(std::move(state)) {}
  19. }

由于现在你不能直接创建FSM类,所以你不得不使用一个更简单/直观的界面的工厂。

  1. auto obj = Fsm::factory::create<MyState1>();
  2. obj->TransitionTo<MyState2>();

它还允许你传递额外的参数来构建你的State类

  1. auto obj = Fsm::factory::create<MyState1>(1, "context", 2.0f);

=====

  1. #include <iostream>
  2. #include <memory>
  3. #include <utility>
  4. using namespace std;
  5. class Fsm;
  6. class State {
  7. public:
  8. virtual ~State() = default;
  9. void SetFsm(Fsm* fsm) { fsm_ = fsm; }
  10. virtual void Enter() = 0;
  11. virtual void Exit() = 0;
  12. protected:
  13. // to allow state changes
  14. Fsm* fsm_{ nullptr };
  15. };
  16. class MyState1 : public State
  17. {
  18. public:
  19. MyState1(){};
  20. virtual void Enter() override {};
  21. virtual void Exit() override {};
  22. };
  23. class MyState2 : public State
  24. {
  25. public:
  26. MyState2(){};
  27. virtual void Enter() override {};
  28. virtual void Exit() override {};
  29. };
  30. class Fsm
  31. {
  32. public:
  33. class factory
  34. {
  35. public:
  36. template <typename T, typename... Args>
  37. static std::unique_ptr<Fsm> create(Args&&... args)
  38. {
  39. auto fsm_ptr = new Fsm(std::make_unique<T>( std::forward<Args>(args)... ));
  40. return std::unique_ptr<Fsm>( fsm_ptr );
  41. }
  42. };
  43. friend class factory;
  44. private:
  45. Fsm(std::unique_ptr<State> state = nullptr) : state_(std::move(state)) {}
  46. public:
  47. template <class T>
  48. void TransitionTo() {
  49. if (state_ != nullptr) {
  50. // if switching to same state, do nothing
  51. const auto temp = std::make_unique<T>();
  52. if (dynamic_cast<T*>(state_.get()) != nullptr) { return; }
  53. state_->Exit();
  54. }
  55. state_ = std::make_unique<T>();
  56. state_->SetFsm(this);
  57. state_->Enter();
  58. }
  59. private:
  60. std::unique_ptr<State> state_;
  61. };
  62. int main()
  63. {
  64. auto obj = Fsm::factory::create<MyState1>();
  65. obj->TransitionTo<MyState2>();
  66. return 0;
  67. }
展开查看全部

相关问题