#include <string>
#include <unordered_map>
#include <iostream>
#include <memory>
template<typename Base>
class Factory{
template<typename, typename>
friend class Registrable;
public:
static Base* create(std::string name){
auto callable = map().at(std::move(name));
return callable();
}
static std::unique_ptr<Base> createUnique(std::string name){
auto callable = map().at(std::move(name));
return std::unique_ptr<Base>(callable());
}
static std::shared_ptr<Base> createShared(std::string name){
auto callable = map().at(std::move(name));
return std::shared_ptr<Base>(callable());
}
private:
static std::unordered_map< std::string, std::function<Base*()> >& map(){
static std::unordered_map< std::string, std::function<Base*()> > map;
return map;
}
template<typename Derived>
static void subscribe(std::string name){
// insert already-exist-check here
std::cout<< "registered: " << name << std::endl;
map().emplace(std::move(name), [](){ return static_cast<Base*>(new Derived{}); });
}
};
template<typename Base, typename Derived>
class Registrable{
protected:
virtual std::string registerName() const = 0;
Registrable(){
isRegistered = true;
}
~Registrable() = default;
static bool init(){
Derived t;
Factory<Base>::template subscribe<Derived>(t.registerName());
return true;
}
private:
static bool isRegistered;
};
template<typename Base, typename Derived>
bool Registrable<Base, Derived>::isRegistered = Registrable<Base, Derived>::init();
struct MyFactoryBase{
virtual ~MyFactoryBase() = default;
virtual void method() const = 0;
};
struct MyFactory1 : public MyFactoryBase, public Registrable<MyFactoryBase, MyFactory1>{
std::string registerName() const override{
return "Class1";
}
void method() const override{ std::cout << "yay Class1" << std::endl; }
MyFactory1() : MyFactoryBase(), Registrable<MyFactoryBase, MyFactory1>(){}
};
struct MyFactory2 : public MyFactoryBase, public Registrable<MyFactoryBase, MyFactory2>{
std::string registerName() const override{
return "Class2";
}
void method() const override{ std::cout << "yay Class2" << std::endl; }
MyFactory2() : MyFactoryBase(), Registrable<MyFactoryBase, MyFactory2>(){}
};
int main(){
auto class1 = std::string("Class1");
auto fac = Factory<MyFactoryBase>::createUnique("Class1");
auto fac2 = Factory<MyFactoryBase>::createShared("Class2");
auto fac3 = Factory<MyFactoryBase>::create(class1);
fac->method();
fac2->method();
fac3->method();
delete fac3;
return 0;
}