Поскольку все функции return new CommandNNN();
, вы можете использовать функцию шаблона:
template <class T>
CommandBase* createCommand() {
return new T();
}
и привязать к этой функции на вашей карте:
map.insert(std::make_pair("Command1", &createCommand<Command1>));
map.insert(std::make_pair("Command2", &createCommand<Command2>));
map.insert(std::make_pair("Command3", &createCommand<Command3>));
Это позволяет вам избежатьсоздание новой функции для каждой команды.Однако в заявлениях map.insert
все равно будет некоторое дублирование.Это может быть дополнительно уменьшено с помощью макросов, если это ваша чашка чая:
#define INSERT(cmd) map.insert(std::make_pair(#cmd, &createCommand<cmd>));
INSERT(Command1);
INSERT(Command2);
INSERT(Command3);
#undef INSERT
или
#define INSERT(n) map.insert(std::make_pair("Command" #n, &createCommand<Command ## n>));
INSERT(1);
INSERT(2);
INSERT(3);
#undef INSERT
Я подозреваю, что вы даже можете заставить препроцессор подсчитать за вас, но это за пределами моего домена.
Применяя еще больше макросов, а также некоторые глобальные состояния, которые многие не одобряют, вы можете получить еще более тесную связь:
#include <map>
#include <string>
#include <cassert>
class CommandBase {};
static std::map<std::string, CommandBase* (*)()> g_commandMap;
template <class C>
CommandBase* createCommand() {
return new C();
}
class CommandRegistrer {
public:
CommandRegistrer(const std::string& name, CommandBase* (*instantiator)()) {
g_commandMap.insert(std::make_pair(name, instantiator));
}
};
#define COMMAND_CLASS(n) \
class Command##n; \
CommandRegistrer g_commandRegistrer##n("Command" #n, createCommand<Command##n>); \
class Command##n : public CommandBase
COMMAND_CLASS(1) { /* implementation here */ };
COMMAND_CLASS(2) { /* implementation here */ };
int main() {
assert(g_commandMap.find("Command1") != g_commandMap.end());
}