#include <iostream>
#include <functional>
#include <map>
#include <typeinfo>
#include <memory>
using namespace std;

struct IAnimal;
struct AnimalFactory
{
    using FactoryFunction = std::function<IAnimal*(std::string)>;
    bool RegisterFunction(std::string name, FactoryFunction f)
    {
        factoryMap.insert(std::make_pair(name,f));
        return true;
    }
    std::unique_ptr<IAnimal> CreateAnimal(std::string name, std::string xml)
    {
        return std::unique_ptr<IAnimal>(factoryMap.at(name)(xml));
    }
    static AnimalFactory &instance()
    {
        static AnimalFactory factory{};
        return factory;
    }

private:
    std::map<std::string, FactoryFunction> factoryMap;

};

struct IAnimal{virtual ~IAnimal(){}};

struct Cat : IAnimal
{
    Cat (std::string xml) {}
    static Cat* CreateAnimal(std::string xml) { return new Cat(xml); }
    static bool registered;
};
bool Cat::registered = AnimalFactory::instance().RegisterFunction("cat", Cat::CreateAnimal);

struct Elephant : IAnimal
{
    Elephant (std::string xml) {}
    static Elephant* CreateAnimal(std::string xml) { return new Elephant(xml); }
    static bool registered;
};
bool Elephant::registered = AnimalFactory::instance().RegisterFunction("elephant", Elephant::CreateAnimal);



int main()
{
    auto cat = AnimalFactory::instance().CreateAnimal("cat","hi");
    auto elephant = AnimalFactory::instance().CreateAnimal("elephant","hi");

    std::cout << typeid(*cat).name() << std::endl;
    std::cout << typeid(*elephant).name() << std::endl;
}
