Реализация шаблона может выглядеть следующим образом:
class Factory {
public:
enum which {
foo, bar, baz
};
template<which w>
A* newA(...);
...
};
template<Factory::which w>
A* Factory::newA(...) {
/* default implementation */
throw invalid_argument();
}
template<>
A* Factory::newA<Factory::foo>(...) {
/* specialization for a 'foo' style A */
...
}
....
Это требует, чтобы значение, используемое для определения того, какой newA
вызывался, было известно во время компиляции. Вы можете потенциально использовать const char *
в качестве параметра шаблона, но это не гарантирует работу на всех компиляторах.
Еще один вариант - создать вспомогательные фабрики, по одному для каждого метода создания фабрики, и сохранить их на карте. Это не является огромным преимуществом по сравнению с хранением указателей на методы, но позволяет определить метод создания по умолчанию и упрощает выборку объектов с карты (нет необходимости проверять, существует ли ключ, потому что вы получите фабрику по умолчанию). С другой стороны, запись для каждого неизвестного ключа будет добавлена на карту.
Кроме того, если вы используете enum
вместо строки для типа ключа, вам не нужно беспокоиться о проверке наличия ключа на карте. Хотя кто-то может передать неверный ключ enum
на newA
, ему придется явно привести аргумент, что означает, что он не собирается делать это случайно. Я с трудом представляю себе случай, когда кто-то намеренно вызвал бы сбой в newA
; потенциальные сценарии включают в себя безопасность, но программист может вывести приложение из строя без использования вашего класса.