#include <iostream>
#include <string>
#include <vector>
#include <map>
std::vector<std::pair<std::string, [type of the object, entity or banana]>> nep; //[type of the object, entity or banana] is my imaginary type
class Entity
{
private:
int x;
public:
Entity(const int x) : x(x) {};
int GetX() const { return x; };
};
class Banana
{
private:
int y;
public:
Banana(const int y) : y(y) {};
int GetY() const { return y; };
};
[type of the object, entity or banana] CreateObj(std::string name) //Used that imaginary variable here again
{
for (unsigned short int i = 0; i < nep.size(); i++)
{
if (nep.at(i).first == name)
{
return [new object with type = nep.at(i).second];
}
}
}
int main()
{
nep.push_back({ "ent", Entity });
nep.push_back({ "banan", Banana });
CreateObj(banan).GetY();
std::cin.get();
}
[тип объекта, сущности или банана] — это моя воображаемая вещь переменного типа.
То, что я хотел бы сделать, это передать туда, например, класс, а затем, используя функцию CreateObj()
, я хотел бы создать новый объект этого типа и использовать его.
Как я могу это сделать?
Вы можете использовать std::variant, он предназначен для таких случаев. (en.cppreference.com/w/cpp/utility/вариант)
Краткий ответ: нет
Длинный ответ:
У вас есть такие инструменты, как std::type_index
и typeid
, но они не будут делать то, что вы хотите.
Однако вы можете сохранить фабричную функцию вместо типа:
using result = std::any; // or some other common type
std::map<std::string, std::function<std::any()>> nep;
nep["banana"] = []{ return Banana{}; };
nep["entity"] = []{ return Entity{}; };
// Call the functions:
result my_banana = nep["banana"]();
Banana& b = std::any_cast<Banana&>(my_banana);
Функции, хранящиеся в карте, создают экземпляры известного типа. Так как карта должна хранить функции одного типа, она должна быть возвращена через общий тип. Этот общий тип может быть std::any
, std::variant<Banana, Entity>
или указателем на базовый класс.
Затем вы можете найти на карте фабричную функцию и вызвать ее, чтобы получить созданный объект. Он должен быть правильно развернут, чтобы получить доступ к переменной через правильный тип для доступа к членам.
Если вы не хотите использовать полиморфизм, вы можете сделать что-то с метапрограммированием:
enum class ClassType {
EntityType,
BananaType,
};
namespace internal {
template <ClassType Type>
struct _build_type {};
template <>
struct _build_type<ClassType::EntityType> {
constexpr auto operator()() {
return EntityType();
}
};
template <>
struct _build_type<ClassType::BananaType> {
constexpr auto operator()() {
return BananaType();
}
};
}
И затем ваш объект конструкции:
template <ClassType Type>
constexpr auto create_instance() {
return internal::_build_type<Type>{}();
}
Итак, вы можете сделать:
const auto object = create_instance<BananaType>();
Эта штука увеличит время компиляции, но не повлияет на производительность во время выполнения.
ИМХО, если вы пытаетесь создавать объекты на лету, подойдет статическая фабрика (фабричный шаблон проектирования). Вы бы представляли свои типы как
enum class
для безопасности типов, а не как строки.