    #include <iostream>
    #include <functional>
    #include <memory>
    #include <unordered_map>

    template <typename BASE>
    struct
    Factory {
        private: using
        TCloneFn = std::function<std::shared_ptr<BASE>(BASE const * const)>;
        
        private:
        static std::unordered_map<BASE const*,TCloneFn> cloneFnMap;
        
        public: template <typename DERIVED_TYPE, typename...TS>
        static std::shared_ptr<BASE>
        create(TS...args) {
            BASE* obj = new DERIVED_TYPE(args...);
            const std::shared_ptr<BASE> pNewObj =
                std::shared_ptr<BASE>(
                    obj,
                    [&](BASE* p){
                        cloneFnMap.erase(p);
                        delete p;
                    }
                );
            
            cloneFnMap[obj] = [&](BASE const * const orig){
                std::shared_ptr<BASE> pClone = create<DERIVED_TYPE>(std::ref(static_cast<DERIVED_TYPE const &>(*orig)));
                return pClone;
            };
            return pNewObj;
        }
        
        public: static std::shared_ptr<BASE>
        clone(std::shared_ptr<BASE const> original) {
            return cloneFnMap[original.get()](original.get());
        }
    };

    template <typename BASE> std::unordered_map<BASE const*,typename Factory<BASE>::TCloneFn> Factory<BASE>::cloneFnMap;

    class Base {
        public: virtual ~Base() throw() {}
        public: virtual void whoAmI() const {
            std::cout << "I am Base instance " << this << "\n";
        }
    };


    class Derived : public Base {
        std::string name;
        public: Derived(std::string name) : name(name) {}
        public: Derived(const Derived&other) : name("copy of "+other.name) {
        }
        private: virtual void whoAmI() const {
            std::cout << "I am Derived instance " << this << " " << name << "\n";
        }
    };

    int main() {
        std::shared_ptr<Base> a = Factory<Base>::create<Derived>("Original");
        a->whoAmI();
        std::shared_ptr<Base> copy_of_a = Factory<Base>::clone(a);
        copy_of_a->whoAmI();
        std::shared_ptr<Base> copy_of_a_copy = Factory<Base>::clone(copy_of_a);
        copy_of_a_copy->whoAmI();
        return 0;
    }



