#include <unordered_map>
#include <typeindex>

template <class Base>
class clone_factory
{
public:
	using function_type = Base*(*)(Base&); // smart pointer/ggf. std::function und so sollten noch ergaenzt werden!

	template <class Derived>
	void register_type(function_type func)
	{
		map_[typeid(Derived)] = func;
	}

	Base* clone(Base &b) const
	{
		return map_.at(typeid(b))(b);
	}

private:
	std::unordered_map<std::type_index, function_type> map_;
};

template <class Base, class Derived, typename FuncT>
void register_types(clone_factory<Base> &clone, FuncT &&head)
{
	clone.template register_type<Derived>(std::forward<FuncT>(head));
}


template <class Base, class Derived, class ... Deriveds, typename FuncT, typename ... FuncTs>
void register_types(clone_factory<Base> &clone,
					FuncT &&head, FuncTs&&... functions) // Syntax geht bestimmt auch schoener.
{
	clone.template register_type<Derived>(std::forward<FuncT>(head));
	register_types<Base, Deriveds...>(clone, std::forward<FuncTs>(functions)...);
}

#include <iostream>

class base {public: virtual ~base() {}};
class derived1 : public base {};
class derived2 : public base {};

base* get_derived1(base &)
{
	std::cout << "derived1\n";
	return nullptr;
}

base* get_derived2(base &)
{
	std::cout << "derived2\n";
	return nullptr;
}

int main() try
{
	clone_factory<base> factory;
	register_types<base, derived1, derived2>(factory, get_derived1, get_derived2);
	derived1 d1;
	derived2 d2;
	factory.clone(d1);
	factory.clone(d2);
}
catch(std::exception &ex)
{
	std::cerr << "Error: " << ex.what() << '\n';
}
