I'm trying to write a policy based auto-registering class using the Curiously Recurring Template Pattern. I decided as design choice to not using registering macro.
Factory Class
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{}); });
}
};
Registrable Class
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();
Client Code Example
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>(){}
};
This code was meant to be in Qt, so originally was with QMap
instead of std::unordered_map
and QString
instead of std::string
, I could have missed something due to the conversion of the code.
There are improvements I could do or issues I'm not considering?
Please review.