你有几个很好的可能性:
PencilBase* createPencil (Colour colour) {
switch (colour) {
case RED:
return new Pencil<RED>();
case BLUE:
return new Pencil<BLUE>();
...
default:
throw std::invalid_argument("Unsupported colour");
}
}
或者为什么不使用像这样的更现代的构造,它的优点是可能在运行时更新:
std::unordered_map<Colour, std::function<PencilBase*()>> FACTORIES = {
{ RED, [](){ new Pencil<RED>(); } },
{ BLUE, [](){ new Pencil<BLUE>(); } },
...
};
PencilBase* createPencil (Colour colour) {
return FACTORIES[colour]();
}
但是,没有人能完全满足您的要求:
当我决定引入新颜色时,我想避免更改此函数(或其助手)。我觉得我们在编译时拥有所有信息来实现这一目标
这至少有两个原因:
- 提供给工厂的颜色参数在运行时已知,而您的模板参数必须在编译时已知。
- 没有用于枚举或遍历所有枚举值的内置解决方案
除了尽可能避免使用模板外,没有多少解决方案可以违背第一点。
就您而言,是否有充分的理由使用模板?你真的需要使用完全不同的类吗?你不能把你的模板改成构造函数中传递的普通参数或作为类成员吗?
如果您别无选择使用模板,有一种方法可以避免重复自己。您可以使用旧的宏和一种通常称为 X 宏的特殊方式。快速示例:
colors.hpp:
COLOUR(RED)
COLOUR(BLUE)
COLOUR(ORANGE)
颜色.hpp:
enum Colour {
#define COLOUR(C) C,
#include "colours.hpp"
#undef COLOUR
INVALID_COLOUR
};
工厂函数:
PencilBase* createPencil (Colour colour) {
switch(colour) {
#define COLOUR(C) case C: return new Pencil<C>();
#include "colours.hpp"
#undef COLOUR
default:
throw new std::invalid_argument("Invalid colour");
}
}
这将基本上重写作为第一个示例给出的开关。您也可以更改宏以重写映射。但是,正如您所看到的,它可能并不比显式更易读或可维护。