У меня есть фабрика, содержащая карту с именами объектов в качестве ключа и указателем для функции значения
template
static T* makeObj()
{
return new T();
}
using createFunction = std::function;
map types;
template
static void add(const std::string& name)
{
types.insert(name, makeObj);
}
Я хочу добавить дополнительную функцию для получения отфильтрованного списка типов (получить список унаследованных классов), примерно так:
template
static std::list getFilteredListOfTypes()
{
}
Вопрос в том, как это сделать.
Первая идея — создать карту со структурой в качестве значения и сохранить там объект соответствующего типа, я могу использовать < strong>dynamic_cast и проверяем все типы, но я сомневаюсь, что создание объекта — хорошая идея.
Другой способ — использовать std::is_base_of:template< class Base, class Derived >
struct is_base_of;
is_base_of принимает два типа: класс Base я могу получить из моего getFilteredListOfTypes, но как получить производный класс? Создайте объект и используйте decltype... но здесь снова создается объект.
Есть ли способ создать такую функцию фильтра без создания объектов?Это плохая идея — создать здесь объект? Разве это плохая идея — создавать объект для каждого элемента карты? Меня немного пугает ситуация, когда на фабрике будут сотни совсем не маленьких типов.
UPD
AppFactory.h:
class AppFactory
{
public:
template
static T* makeObj()
{
return new T();
}
using createFunction = std::function;
using registerMap = tsl::robin_map;
static registerMap& get();
template
static std::unique_ptr createUnique(const std::string& name)
{
return std::unique_ptr(create(name));
}
template
static std::shared_ptr createShared(const std::string& name)
{
return std::shared_ptr(create(name));
}
template
static T* create(const std::string& name)
{
if(get().contains(name))
{
return static_cast(get()[name]());
}
return nullptr;
}
template
static bool add(const std::string& name)
{
auto resultPair = get().insert_or_assign(name, makeObj);
return resultPair.second;
}
};
#define APPFACTORY_ADD(classname) \
namespace { static bool addName = AppFactory::add(#classname); }
AppFactory.cpp:
AppFactory::registerMap& AppFactory::get()
{
static AppFactory::registerMap map;
return map;
}
Использование фабрики:
...
APPFACTORY_ADD(SomeClass);
...
AppFactory::createUnique("SomeClass")
...
UPD 2
тестовая реализация getFilteredListOfTypes
struct typedata
{
createFunction func;
Object* obj;
};
using registerMap = tsl::robin_map;
...
template
static bool add(const std::string& name)
{
typedata data;
data.func = makeObj;
data.obj = new T();
auto resultPair = get().insert_or_assign(name, data);
return resultPair.second;
}
...
template
static std::list getFilteredListOfTypes()
{
std::list typeList;
for(auto it = get().begin(); it != get().end(); ++it)
{
if(dynamic_cast(get()[it->first].obj))
{
typeList.push_back(it->first);
}
}
return typeList;
}
Использование getFilteredListOfTypes
class A : public Object
...
class B : public A
...
class C : public B
...
class D : public C
...
class E : public B
...
lst = AppFactory::getFilteredListOfTypes(); // lst -> {"A", "B", "C", "D", "E"}
lst = AppFactory::getFilteredListOfTypes(); // lst -> {"B", "C", "D", "E"}
lst = AppFactory::getFilteredListOfTypes(); // lst -> {"C", "D"}
lst = AppFactory::getFilteredListOfTypes(); // lst -> {"D"}
Подробнее здесь: https://stackoverflow.com/questions/786 ... he-factory