Как бы я использовал type в качестве «переменной»?

#c

#c

Вопрос:

 #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() функции я хотел бы создать новый объект этого типа и использовать его.
Как я могу это сделать?

Комментарии:

1. ИМХО, если вы пытаетесь создавать объекты на лету, статическая фабрика (шаблон проектирования фабрики) была бы уместна. Вы бы представляли свои типы как enum class для безопасности типов, а не как строки.

2. Вы можете использовать std::variant , он предназначен для таких случаев. ( en.cppreference.com/w/cpp/utility/variant )

Ответ №1:

Короткий ответ: нет

Длинный ответ:

У вас есть такие инструменты, как 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"]();
Bananaamp; b = std::any_cast<Bananaamp;>(my_banana);
  

Функции, хранящиеся в map, создают экземпляры известного типа. Поскольку карта должна хранить функции одного и того же типа, она должна быть возвращена через общий тип. Этот общий тип может быть std::any , std::variant<Banana, Entity> или указателем на базовый класс.

Затем вы можете выполнить поиск по карте для заводской функции и вызвать ее, чтобы получить созданный объект. Он должен быть правильно развернут, чтобы получить доступ к переменной через правильный тип для доступа к членам.

Ответ №2:

Если вы не хотите использовать полиморфизм, вы можете что-то сделать с помощью метапрограммирования:

 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>();
  

Это увеличит время компиляции, но не приведет к снижению производительности во время выполнения.