1
#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();
}

[type of the object, entity or banana] is my imaginary variable-type thing. What I'd like to do is pass there a class for example, and then using CreateObj() function I'd like to create new object of that type and use it. How can I do that?

2
  • IMHO, if you are trying to create objects on the fly, a static factory (factory design pattern) would be appropriate. You'd represent your types as an enum class for type safety rather than strings. Commented Apr 6, 2019 at 21:13
  • 1
    You can use std::variant, it is designed for those cases. (en.cppreference.com/w/cpp/utility/variant) Commented Apr 6, 2019 at 21:14

2 Answers 2

3

Short answer: no

Long answer:

You have tools like std::type_index and typeid, but they won't do what you want.

You can however store factory function instead of a type:

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

The functions stored in the map create instances of a known type. Since the map has to store functions of the same type, it must be returned through a common type. That common type can be std::any, std::variant<Banana, Entity> or a pointer to a base class.

Then you can search the map for a factory function and call it to get the created object. It must be unwrapped correctly to access the variable through the right type to access members.

Sign up to request clarification or add additional context in comments.

Comments

2

If you do not want to use polymorphism, you can do something with meta-programming:

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

And then, your construct object:

template <ClassType Type>
constexpr auto create_instance() {
    return internal::_build_type<Type>{}();
}

So you can do:

const auto object = create_instance<BananaType>();

This thing will increase your compilation time but it does not have any performance penalty during runtime.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.