假设一个人想要创建一个具有两个独立实现的 C++ 类(假设一个在 CPU 和 GPU 上运行),而一个人希望这在编译时发生。
可以为此使用什么设计模式?
一本值得阅读的好书是:Andrei Alexandrescu 撰写的 Modern C++ Design: Generic Programming and Design Patterns Applied。
基本上他说你可以使用基于策略的类来实现你想要的(一种策略模式,但在编译时完成。下面是一个简单的例子,展示了这一点:
#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();
}
最简单的解决方案示例,使用策略模式(但是,选择编译时还是运行时无关紧要):
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())
or 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>
在程序开始时。
或者您可以使用 Omaha 提供的解决方案#ifdef
。
您可以为此使用一个简单的模板。(对不起,粗略的实现,这只是一个例子)
#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'
}
如果你想在编译时做出决定,总是有旧的备用:预处理器。使用#ifdef
/#endif
块和编译器参数来指定你想要的代码。