在编译时选择实现

Choose between implementations at compile time

本文关键字:实现 选择 编译      更新时间:2023-10-16

假设一个人想创建一个具有两个独立实现的C++类(比如一个在CPU和GPU上运行),并且希望在编译时发生这种情况。

可以使用什么设计模式?

一本好书是:现代C++设计:通用编程和设计模式应用,作者是Andrei Alexandrescu。

基本上,他说你可以使用基于策略的类(一种策略模式,但在编译时完成)来实现你想要的东西。贝娄是一个简单的例子,展示了这一点:

#include <iostream>
using namespace std;
template <typename T>
struct CPU
{
  // Actions that CPU must do (low level)
  static T doStuff() {cout << "CPU" << endl;};
};
template <typename T>
struct GPU
{
  // Actions that GPU must do (low level)
  // Keeping the same signatures with struct CPU will enable the strategy design patterns
  static T doStuff() {cout << "GPU" << endl;};
};
template <typename T, template <class> class LowLevel>
struct Processors : public LowLevel<T>
{
  // Functions that any processor must do
  void process() {
    // do anything and call specific low level
    LowLevel<T>::doStuff();
  };
};
int main()
{
  Processors<int, CPU> cpu;
  Processors<int, GPU> gpu;
  gpu.process();
  cpu.process();
}
最简单的

解决方案示例,使用 Strategy 模式(但是,选择编译时还是运行时都无关紧要):

class BaseStrategy
{
  public:
    virtual void doStuff() = 0;  
};
class Strategy1 : public Base
{
  public:
    void doStuff();
};
class Strategy2 : public Base
{
  public:
    void doStuff();
};
class SomeKindOfAMainClass
{
  public:
    SomeKindOfAMainClass(BaseStrategy* s)
    {
      this->s = s; 
    }
    void doStuff()
    {
      s->doStuff();
    }
  private:
    BaseStrategy* s;
};

然后你只需做new SomeKindOfAMainClass(new Strategy1())new SomeKindOfAMainClass(new Strategy2()).

特征的简单示例:

struct WithStrategy1 {};
struct WithStrategy2 {};
template<typename T>
class SomeKindOfAMainClass;
template<>
class SomeKindOfAMainClass<WithStrategy1>
{
  //use Strategy1 here
};
template<>
class SomeKindOfAMainClass<WithStrategy2>
{
  //use Strategy2 here
};

您只需在程序开始时实例化SomeKindOfAMainClass<WithStrategy1>SomeKindOfAMainClass<WithStrategy2>

或者你可以得到奥马哈给出的解决方案#ifdef.

您可以使用一个简单的模板。(抱歉粗略的实现,这只是一个例子)

#include <iostream>
struct example
{
    void cpu() { std::cout << "Cpun"; }
    void gpu() { std::cout << "Gpun"; }
    template<bool useGpu = true>void go() { gpu(); }
};
template<>void example::go<false>() { cpu(); }
int main()
{
    example().go<false>(); //<-- Prints 'Cpu'
    example().go(); // <-- Prints 'Gpu'
}

如果要做出编译时决策,则始终存在旧的备用数据库:预处理器。 使用 #ifdef/#endif 块和编译器参数来指定所需的代码。