0
\$\begingroup\$

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

LIVE EXAMPLE

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.