C++ Class for optionally constructing arbitrary derived classes Here is a class I'm working up to register classes derived from a Module base class. These classes may or may not be instantiated (via the ModuleCreatorBase::create() method) based on some logic which is not yet included in the code.

I wanted to allow constructing Modules which take no arguments and Modules which take any number of arguments, though I'm not sure if my method here is the best approach for that. For some reason it feels kind of clunky to me.

Are there more effective or perhaps other more well established ways to achieve this?

#include &lt;memory&gt;
#include &lt;unordered_map&gt;
#include "Module.hpp"

class ModuleManager
{
public:
  template &lt;typename ModuleClass&gt;
  static void registerModule(const std::string&amp; moduleName);
  template &lt;typename ModuleClass, typename... Args&gt;
  static void registerModule(const std::string&amp; moduleName, Args&amp;&amp;... args);
private:
  struct ModuleCreatorBase
  {
    virtual std::unique_ptr&lt;Module&gt; create() = 0;
  };
  template &lt;typename ModuleClass&gt;
  struct ModuleCreator : public ModuleCreatorBase
  {
    std::unique_ptr&lt;Module&gt; create() override;
  };
  template &lt;typename ModuleClass, typename... Args&gt;
  struct ModuleCreatorArgs : public ModuleCreatorBase
  {
    ModuleCreatorArgs(Args&amp;&amp;... args);
    std::tuple&lt;Args...&gt; args;
    template&lt;std::size_t ...I&gt;
    std::unique_ptr&lt;Module&gt; do_create(std::index_sequence&lt;I...&gt;);
    std::unique_ptr&lt;Module&gt; create() override;
  };
  static std::unordered_map&lt;std::string, ModuleCreatorBase*&gt; registry;
};

template &lt;typename ModuleClass&gt;
std::unique_ptr&lt;Module&gt; ModuleManager::ModuleCreator&lt;ModuleClass&gt;::create()
{
  return std::make_unique&lt;ModuleClass&gt;();
}

template &lt;typename ModuleClass, typename... Args&gt;
ModuleManager::ModuleCreatorArgs&lt;ModuleClass, Args...&gt;::ModuleCreatorArgs(Args&amp;&amp;... args)
: args(std::forward&lt;Args&gt;(args)...) {}

template &lt;typename ModuleClass, typename... Args&gt;
std::unique_ptr&lt;Module&gt; ModuleManager::ModuleCreatorArgs&lt;ModuleClass, Args...&gt;::create()
{
  return do_create(std::index_sequence_for&lt;Args...&gt;{});
}

template &lt;typename ModuleClass, typename... Args&gt;
template &lt;std::size_t ...I&gt;
std::unique_ptr&lt;Module&gt; ModuleManager::ModuleCreatorArgs&lt;ModuleClass, Args...&gt;::do_create(std::index_sequence&lt;I...&gt;)
{
  return std::make_unique&lt;ModuleClass&gt;(std::get&lt;I&gt;(args)...);
}

template &lt;typename ModuleClass&gt;
void ModuleManager::registerModule(const std::string&amp; moduleName)
{
  registry.insert(std::pair&lt;std::string, ModuleCreatorBase*&gt;(moduleName, new ModuleCreator&lt;ModuleClass&gt;()));
}
template &lt;typename ModuleClass, typename... Args&gt;
void ModuleManager::registerModule(const std::string&amp; moduleName, Args&amp;&amp;... args)
{
  registry.insert(std::pair&lt;std::string, ModuleCreatorBase*&gt;(moduleName, new ModuleCreatorArgs&lt;ModuleClass, Args...&gt;(std::forward&lt;Args&gt;(args)...)));
}
Unconstrained templates
The public facing member function templates registerModule never validate any of the types they take. Currently, trying to call registerModule for a type not derived from Module fails due to the instantiation of ModuleCreator::create (and subsequent missing conversion from ModuleClass to Module), this relies on an implementation detail (which might change).
Similarly, the overload of registerModule which takes constructor arguments never validates whether ModuleClass can actually be constructed with them.
Better be explicit about which types are allowed to be passed!
In C++17, one could use a simple if constexpr, but since this question is tagged c++14, using SFINAE is the only option.
Even better, with slightly more work you can give much better error messages than what the compiler generates, so a user of the class doesn't have to parse dozens of lines of template instantiations.
Example using SFINAE (just member function declaration), assuming below fix for ModuleCreatorArgs::args:
template&lt;typename ModuleClass&gt;
static std::enable_if_t&lt;
    std::is_base_of&lt;Module, ModuleClass&gt;::value, void&gt; &amp;&amp;
    std::is_default_constructible&lt;ModuleClass&gt;::value,
void&gt; registerModule(const std::string&amp;);

template&lt;typename ModuleClass, typename... Args&gt;
static std::enable_if_t&lt;
    std::is_base_of&lt;Module, ModuleClass&gt;::value &amp;&amp;
    std::is_constructible&lt;ModuleClass, std::remove_reference_t&lt;Args&gt;...&gt;::value,
void&gt; registerModule(const std::string&amp;, Args&amp;&amp;...);

For error messages, you could add:
template&lt;typename ModuleClass, typename...Args&gt;
static std::enable_if_t&lt;
    !std::is_base_of&lt;Module, ModuleClass&gt;::value ||
    !std::is_constructible&lt;ModuleClass, std::remove_reference_t&lt;Args&gt;...&gt;::value,
void&gt; registerModule(const std::string&amp;, Args&amp;&amp;...)
{
    static_assert(std::is_base_of&lt;Module, ModuleClass&gt;::value, &quot;ModuleClass needs to be derived from Module!&quot;);
    static_assert(std::is_constructible&lt;ModuleClass, std::remove_reference_t&lt;Args&gt;...&gt;::value, &quot;ModuleClass is not constructible from the given arguments!&quot;);
}

Memory and lifetime management
ModuleManager leaks all created instance of ModuleCreatorBase stored in ModuleManager::registry, as delete is never called. Why not simple use std::unique_ptr&lt;ModuleCreatorBase&gt; instead of ModuleCreatorBase*? (Note: adding calls to delete in the destructor of ModuleManager doesn't fix this problem!)
A bit subtler is the dangling reference issue with ModuleCreatorArgs: Since all the passed arguments are perfectly forwarded to be stored in ModuleCreatorArgs::args, lvalue references (to possibly local values!) will be stored as references, which might dangle when they are actually used for Module construction.
Now, I don't know the requirements for Modules derived classes: Do they need to take references in their constructors (e.g. for non-copyable non-movable objects) that for some reason cannot be passed as pointers?

If no, this gets simple: Change the type of ModuleCreatorArgs::args to std::tuple&lt;std::remove_reference_t&lt;Args&gt;...&gt; so every argument is either moved or copied (as appropriate).
If yes, this will require good documentation and discipline! (Honestly, if you can, try to avoid this mess. This is easy to screw up and hard to get right at the callsite to ModuleManager::registerModule.)

Final notes
I really hopes this class (ModuleManager) gets expanded so it can actually be used to construct objects (all it currently does is creating private state). Maybe add a ModuleManager::create(const std::string&amp;) method?
Also, I don't know your actual use case of Modules, but if you expect them to be shared quite often, you might want to add a create_shared (or similarly named) method that returns a std::shared_ptr&lt;Module&gt; instead.