繁体   English   中英

在运行时更改变量的模板类型

[英]Changing template type of a variable at runtime

我在编写 state 机器时遇到问题,该机器将在执行期间切换基于模板的变量。 目前,实现如下:

template <typename TemplateT>
class InnerClass {
  void foo();
}

class StateMachine {
public:
  std::unique_ptr<InnerClass<ParticularType>> inner;

  void someMethod() {
    ...
    inner->foo();
    ...
  }
}

我需要概括这个实现,以便StateMachine有一个成员,可以将inner变量更改为不同的基于模板的类型:

void StateMachine::changeState(int state) {
  switch(state) {
  case 0:
    inner.reset(new InnerClass<ParticularType0>());
    break; 
  case 1:
    inner.reset(new InnerClass<ParticularType1>());
    break; 
  case 2:
    inner.reset(new InnerClass<ParticularType2>());
    break;
  ...
  default:
    assert();
  }
}

我知道只有在编译时知道类型时才能使用模板,因此,很可能应该有另一种我不知道的方法。 您能否指出一些可以在这里应用的想法? 除了使用创建InnerClass的无模板接口之外,还有其他方法吗:

class InnerClassInterface {
  virtual void foo() = 0;
}

template <typename TemplateT>
class InnerClass : InnerClassInterface {
  virtual void foo() override;
}

因此,很可能应该有另一种我不知道的方法

不幸的是,没有。 就像您说的那样,模板是在编译时评估的。 这意味着除非您键入所有可能的InnerClass类型参数,就像您在 switch 语句中所做的那样,否则编译器将无法知道要实例化InnerClass模板的哪些实例。

您最好完全改变您的设计并使用某种形式的多态性。

但如果你真的想保留这种设计,一种解决方案可能是将不同版本的ParticularType放入专门的 class 模板中。 我已将ParticularType重命名为State并将其不同版本更改为一些 state 名称,因为我假设ParticularType是为了代表状态。

// states.h
enum
{
    STATE_WALKING,
    STATE_RUNNING,
    STATE_SHOOTING
    ...
};
// state.h
class StateBase
{
public:
    // Insert what your states actually do here
    //        |
    //        V
    virtual void someStateFunc() = 0;
};

template<int I>
class State
{
};

template<>
class State<STATE_WALKING> : public StateBase
{
public:
    // Code for walking state
    void someStateFunc() override
    {
        ...
    }
};

template<>
class State<STATE_RUNNING> : public StateBase
{
public:
    //Code for running state
    void someStateFunc() override
    {
        ...
    }
};

template<>
class State<STATE_SHOOTING> : public StateBase
{
    // Code for shooting state
    ...
};

...

在您的示例代码中,您将inner声明为std::unique_ptr<InnerClass<ParticularType>>类型。 这将无法编译,因为您尝试将类型为InnerClass<ParticularType0>InnerClass<ParticularType1>unique_ptr分配给inner changeState 不过,这很容易解决,您只需要一个基础InnerState即可继承 InnerState。

下面是InnerClassStateMachine的样子:

class InnerClassBase
{
public:
    virtual void foo() = 0;
    ...
};

template<typename T>
class InnerClass : public InnerClassBase
{
public:
    void foo() override
    {
        ...
    }
};

class StateMachine {
public:
    std::unique_ptr<InnerClassBase> inner;

    void someMethod() {
      ...
      inner->foo();
      ...
    }

    template<int S>
    void changeState() {
        inner.reset(new InnerClass<State<S>>());
    }
};

并这样称呼它:

#include "states.h"

...

if(some_condition)
{
    stateMachine.changeState<STATE_SHOOTING>();
}
...

每次您想添加新的 state 时,只需向State添加新的专业化。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM