Как получить объект неизвестного класса с заданным именем класса
-
20-09-2019 - |
Вопрос
Я ищу способ определить во время выполнения, какой тип объекта следует выделить (на основе заданного имени класса, который имеет тип const char*
).
Ну, самый простой способ, конечно, это использовать множество if
с /else if
s, но это не кажется применимым, потому что у меня более 100 различных классов (ну, по крайней мере, все они происходят от одного базового класса), и мне также приходится довольно регулярно добавлять новые классы.
Я уже придумал первый черновик, но, к сожалению, он еще не компилируется (mingw & g++ 4.4).
template<typename TBase, typename TDerived, typename... TArgs>
Base* get_classobject(const char* classname)
{
if(strcmp(classname,typeid(TDerived).name())==0)
return new TDerived; //
else if(sizeof...(TArgs)>0)
return get_classobject<TBase,TArgs...>(classname);
else
return 0;
}
int main()
{
Base* obj = get_classobject<Base,A,Foo,B,C>("Foo");
// ^- Types A B C and Foo are all derived from Base
delete obj; //of course we got an virtual dtor ;)
return 0;
}
но затем sizeof...(TArgs)>0
не мешает gcc пытаться сгенерировать код для get_classobject<TBase,const char*>(const char*)
который терпит неудачу
Есть ли у вас идеи, как это исправить, или какие-либо другие идеи?Спасибо.
РЕДАКТИРОВАТЬ:я решил это:
template<typename TBase, typename TDerived>
Base* get_classobject(const char* classname)
{
if(strcmp(classname,typeid(TDerived).name())==0)
return new TDerived;
return 0;
}
template<typename TBase, typename TDerived, typename TArg, typename... TArgs>
Base* get_classobject(const char* classname)
{
if(strcmp(classname,typeid(TDerived).name())==0)
return new TDerived;
return get_classobject<TBase,TArg,TArgs...>(classname);
}
РЕДАКТИРОВАТЬ Для заинтересованных читателей:
Теперь вы должны понять, что приведенная выше реализация вообще НЕ является независимой от компилятора.Выход typeif(sometype).name()
зависит от компилятора/реализации.Используя static const char* name
переменная или функция внутри всех производных классов исправит это, но добавит кучу работы (конечно, вы можете использовать для этого макрос, но если вы уже используете макросы, вы также можете использовать другой метод фабрики объектов)
Решение
Не могли бы вы просто заявить
template<typename TBase, typename TDerived, typename TArg, typename... TArgs>
?
Тогда вы можете специализироваться на случае
typename TBase, typename TDerived, typename TArg
Другие советы
Прочтите ответы дальше здесь, вам, вероятно, понадобится фабрика.
Как насчет создания специализированного метода get_classobject() без различных шаблонов?Это остановит рекурсию.
Тогда у вас будет одно определение с вариационным шаблоном, а другое - просто template<typename TBase, typename TDerived>
.Другая идея — создать нешаблонную перегрузку, которая принимает только const char* и возвращает 0.
Похоже, вы ищете классический шаблон фабрики объектов.Посмотри на это вопрос о переполнении стека.Лично мне это нравится метод