2
\$\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\$
0

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.