C++模板设计问题

发布于 2024-10-29 21:10:56 字数 1843 浏览 3 评论 0原文

我有一个用 C++ 编写的模型,它基于运行时多态性和虚函数。该模型按原样工作完全正常。我想研究将其转换为模板和编译时多态性。原因是:

  1. 模型中只有一个类在运行时真正是动态的,其余的都是编译时决定。多态纯粹是为了让模型的改变更容易、更灵活。
  2. 我想在模型中内联几个小函数,这对于虚拟函数来说是不可能的。

这是我的模型现在的一个简化的假设示例:

class Particle
{
public:
  // ...
  virtual void move();
};

class Electron : public Particle  { /*...*/ };


// Physics Models /////////////////////////////////

class PhysicsModel
{
public:
  // ...
  virtual void doStuffWithParticles();
private:
  Particle* theParticle;
};

class NewtonPhysics : public PhysicsModel  { /*...*/ };
class QuantumPhysics : public PhysicsModel  { /*...*/ };


// SimulationModels ////////////////////////////

class SimulationModel
{
public:
  virtual void runSimulation();
  // ...
private:
  PhysicsModel* thePhysics;
  Particle* theParticle;
};

class HadronCollider : SimulationModel { /*...*/ };

但是假设我想内联粒子函数,例如 move(),因为它是一系列 for 循环的内部循环,并且可以大大受益于速度加成。在编译时,我知道我正在运行什么物理模型和模拟模型,但粒子是运行时决定的。

那么,怎么样:

template <typename TParticleType>
class PhysicsModel
{
  // ...
  TParticleType theParticle;
};

template <typename TParticleType,
          typename TPhysicsModelType>
class SimulationModel
{
  TParticleType theParticle;
  TPhysicsModelType theModel;
};

好的,到目前为止一切顺利。但现在假设在编译时我决定使用运行强子模拟和量子物理模型,并且我们正在读取粒子的输入文件。我想避免这种风格的东西:

int main()
{ 
  // ...
  switch( getUserInput()->currentParticleType )
  {
     case ELECTRON:  HadronSimulation<Electron, QuantumPhysics>.run();
     case PROTON:    HadronSimulation<Proton, QuantumPhysics>.run();
     // ...
  }
}

......并且宁愿将“QuantumPhysics”类型放在其他地方,这样它就在同一个地方。这是一个过于简单化的示例,实际上我有大约 4-5 个参数,它们是编译时决策。

基本上,我正在寻找一种设计,使我能够将运行时参数放入此类模板框架中。有没有好的方法可以做到这一点?如果这看起来像一个愚蠢的问题,请道歉,但我对 C++ 中的模板完全陌生。提前致谢。

I have a model written in C++ which is based on run-time polymorphism and virtual functions. The model works completely fine as is. I'd like to investigate converting this to templates and compile-time polymorphism. The reasons are that:

  1. Only one class in the model is truly dynamic at run-time, the rest are compile-time decisions. The polymorphism is purely to make changes in the model easier and more flexible.
  2. I would like to inline several small functions in the model, which is impossible with virtual functions.

Here is a simplified hypothetical example of what my model looks like now:

class Particle
{
public:
  // ...
  virtual void move();
};

class Electron : public Particle  { /*...*/ };


// Physics Models /////////////////////////////////

class PhysicsModel
{
public:
  // ...
  virtual void doStuffWithParticles();
private:
  Particle* theParticle;
};

class NewtonPhysics : public PhysicsModel  { /*...*/ };
class QuantumPhysics : public PhysicsModel  { /*...*/ };


// SimulationModels ////////////////////////////

class SimulationModel
{
public:
  virtual void runSimulation();
  // ...
private:
  PhysicsModel* thePhysics;
  Particle* theParticle;
};

class HadronCollider : SimulationModel { /*...*/ };

But say if I want to inline the Particle functions, like move(), because it's the inner loop of a series of for-loops and could greatly benefit from the speed bonus. And at compile-time, I know what physics model and simulation model I'm running, but the Particle is a run-time decision.

So, how about:

template <typename TParticleType>
class PhysicsModel
{
  // ...
  TParticleType theParticle;
};

template <typename TParticleType,
          typename TPhysicsModelType>
class SimulationModel
{
  TParticleType theParticle;
  TPhysicsModelType theModel;
};

Okay, so far so good. But now lets say at compile time I've decided we're using running the Hadron Simulation, with Quantum Physics model, and we're reading in an input file of particles. I want to avoid something of this flavor:

int main()
{ 
  // ...
  switch( getUserInput()->currentParticleType )
  {
     case ELECTRON:  HadronSimulation<Electron, QuantumPhysics>.run();
     case PROTON:    HadronSimulation<Proton, QuantumPhysics>.run();
     // ...
  }
}

... and would rather put the "QuantumPhysics" type somewhere else so it's just in the same place. This is an oversimplified example, and actually I would have about 4-5 parameters which are compile-time decisions.

Basically I'm looking for a design that allows me to fit in a run-time parameter into this sort of template framework. Is there a good way to do this? Apologize if this seems like an idiotic question, but I'm completely new to templates in C++. Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

北座城市 2024-11-05 21:10:56

静态和动态多态性不能很好地混合,并且在它们相互作用的情况下,需要某种形式的分支来将运行时信息转变为静态配置变体中的选择。您可以使用简单的类型生成器来至少减少物理模型的重复:

template< class Particle >
class HadronSimulationGenerator {
public:
   typedef HadronSimulation< Particle, QuantumPhysics > type;
};

int main()
{ 
  // ...
  switch( getUserInput()->currentParticleType )
  {
     case ELECTRON:  HadronSimulationGenerator<Electron>::type.run();
     case PROTON:    HadronSimulationGenerator<Proton>::type.run();
     // ...
  }
}

没那么漂亮。

Static and dynamic polymorphism do not mix well, and where they interact with one another, some form of branching is required to turn run-time information into a choice among statically configured variants. You could use a simple type generator to at least reduce the repetition of your physics model:

template< class Particle >
class HadronSimulationGenerator {
public:
   typedef HadronSimulation< Particle, QuantumPhysics > type;
};

int main()
{ 
  // ...
  switch( getUserInput()->currentParticleType )
  {
     case ELECTRON:  HadronSimulationGenerator<Electron>::type.run();
     case PROTON:    HadronSimulationGenerator<Proton>::type.run();
     // ...
  }
}

Not much prettier.

孤檠 2024-11-05 21:10:56

您如何修复第一个示例中的 PhysicsModelParticleType(没有模板)?构造函数负责实例化两者吗?如果是,那么您可以使用类似的技术通过在 SimulationModel 的构造函数中执行 switch 来向用户隐藏这一点。

class SimulationModel {
    void run() {
        switch(currentPhysicsMode) {
        case QUANTUM:
            switch(currentParticleType) {
                case ELECTRON:
                    SimulationModelImpl<Electron, QuantumPhysics>::run();
                    break;
                case PROTON:
                    SimulationModelImpl<Proton, QuantumPhysics>::run();
                    break;
                ...
            }
        }
    }
};

template <typename TParticleType,
      typename TPhysicsModelType>
class SimulationModelImpl {
    TParticleType theParticle;
    TPhysicsModelType theModel;
    ...
};

How did you fix your PhysicsModel and ParticleType in the first example (without templates)? Was the constructor responsible for instantiating both? If yes, then you can use a similar technique to hide this from the user by doing your switch in the constructor of SimulationModel.

class SimulationModel {
    void run() {
        switch(currentPhysicsMode) {
        case QUANTUM:
            switch(currentParticleType) {
                case ELECTRON:
                    SimulationModelImpl<Electron, QuantumPhysics>::run();
                    break;
                case PROTON:
                    SimulationModelImpl<Proton, QuantumPhysics>::run();
                    break;
                ...
            }
        }
    }
};

template <typename TParticleType,
      typename TPhysicsModelType>
class SimulationModelImpl {
    TParticleType theParticle;
    TPhysicsModelType theModel;
    ...
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文