#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;
}