samedi 16 février 2019

Auto Registering Factory not working useless derived class has user defined constructor

I am writing an auto registering factory Factory that registers a static method Create from a wrapper BaseWrapper around Baseclass. Derived class inherits from Base class using BaseWrapper. I used CRTP so that I don't need to add Create function in every Derived class.

I referred to this super neat tutorial -- http://www.nirfriedman.com/2018/04/29/unforgettable-factory/

The problem is that it only registers the Create function if there is an user defined constructor of the derived class otherwise it does not and the assertion in the code fails. I am failing to understand why is it happening and how can I solve it without an user defined constructor.

(For brevity, I removed a lot of code)

#include <iostream>
#include <map>
#include <string>

struct Base {
    virtual ~Base() = default;
};

using Func = std::function<Base*()>;
using FactoryMap = std::map<std::string, Func>;

struct Factory {   
    static FactoryMap& GetMap() {
        static FactoryMap map;
        return map;
    }
    static std::size_t GetSize() {
        return GetMap().size();
    }
    static Func GetFunc(const std::string& name) {
        return (HasFunc(name)) ? GetMap()[name] : nullptr;
    };
    static bool HasFunc(const std::string& name) {
        auto& map = GetMap();
        auto it = map.find(name);
        return (it != std::end(map)) ? true : false;
    };
    static bool Register(const std::string & name, Func func) {
        if (!HasFunc(name)) {
            GetMap()[name] = func;
        }
        return true;
    }
};

template <typename Derived>
struct BaseWrapper : public Base {
    static Base* Create() {
        return new Derived();
    }
    BaseWrapper() { (void) registered; };
    static bool registered;
};
template <typename Derived>
bool BaseWrapper<Derived>::registered = Factory::Register(Derived::Name(), BaseWrapper<Derived>::Create);

struct Derived1 : public BaseWrapper<Derived1> {
    static std::string Name() {
        return "Derived1";
    }
    // only works if I uncomment this.
    // Derived1(){};
};

int main() {
    Base* base_ptr = Factory::HasFunc("Derived") ? Factory::GetFunc("Derived")() : nullptr;
    assert(base_ptr != nullptr); // assertion fails
}

Aucun commentaire:

Enregistrer un commentaire