简体   繁体   中英

Choose between implementations at compile time

Say one wants to create a C++ class with two separate implementations (say one to run on a CPU and on a GPU) and one wants this to happen at compile time.

What design pattern can be used for this?

A good book to read is: Modern C++ Design: Generic Programming and Design Patterns Applied, written by Andrei Alexandrescu.

Basicly he said that you can implement what you want using policy based class (a kind of strategy pattern, but done at compilation time. Bellow is a simple example showing this:

#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();
}

You can use a simple template for that. (Sorry for the crude implementation, this is just an example)

#include <iostream>
struct example
{
    void cpu() { std::cout << "Cpu\n"; }
    void gpu() { std::cout << "Gpu\n"; }

    template<bool useGpu = true>void go() { gpu(); }
};
template<>void example::go<false>() { cpu(); }

int main()
{
    example().go<false>(); //<-- Prints 'Cpu'
    example().go(); // <-- Prints 'Gpu'
}

Simplest solution example, using the Strategy pattern (however, it's irrelevant whether it's compile-time or run-time chosen):

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

and then you just do either new SomeKindOfAMainClass(new Strategy1()) or new SomeKindOfAMainClass(new Strategy2()) .

Simple example of traits:

struct WithStrategy1 {};
struct WithStrategy2 {};

template<typename T>
class SomeKindOfAMainClass;

template<>
class SomeKindOfAMainClass<WithStrategy1>
{
  //use Strategy1 here
};

template<>
class SomeKindOfAMainClass<WithStrategy2>
{
  //use Strategy2 here
};

And you just either instantiate SomeKindOfAMainClass<WithStrategy1> or SomeKindOfAMainClass<WithStrategy2> at the beginning of your program.

Or you can have the solution given by Omaha with #ifdef .

If you want to make compile-time decisions, there is always the old standby: the preprocessor. Use #ifdef / #endif blocks and compiler arguments to specify the code you want.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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