C++ Registry pattern implementation I created a template registry class. It supports custom factory functions and custom constructors. Any kind of feedback is welcome (style, performance, bugs)

registry.hpp:

#ifndef REGISTRY_HPP
#define REGISTRY_HPP

//STL
#include &lt;unordered_map&gt;
#include &lt;memory&gt;

template&lt;typename Key&gt;
class RegistryConstructionError : public std::exception
{
public:
    RegistryConstructionError(const Key &amp;key)   :key(key){}

    const char *what()const throw(){return "Undefined key";}
    const Key key;
};

template&lt;typename Base, typename Key, typename... Args&gt;
class Registry
{
public:
    typedef std::unique_ptr&lt;Base&gt; (*FactoryFunc)(Args... args);

    Registry() = default;
    ~Registry() = default;

    template&lt;typename Derived&gt;
    void registerClass(const Key &amp;key);
    void registerFactory(const Key &amp;key, const FactoryFunc factory);

    std::unique_ptr&lt;Base&gt; construct(const Key &amp;key, Args... args);

private:
    template&lt;typename Derived&gt;
    static std::unique_ptr&lt;Base&gt; constructDerived(Args... args);

    std::unordered_map&lt;Key, FactoryFunc&gt; m_map;

public:
    typedef RegistryConstructionError&lt;Key&gt; ConstrError;
};

#include "registry.tpp"

#endif // REGISTRY_HPP


registry.tpp:

template&lt;typename Base,
        typename Key,
        typename... Args&gt;
template&lt;typename Derived&gt;
void Registry&lt;Base, Key, Args...&gt;::registerClass(const Key &amp;key)
{
    m_map[key] = &amp;constructDerived&lt;Derived&gt;;
}

template&lt;typename Base,
        typename Key,
        typename... Args&gt;
void Registry&lt;Base, Key, Args...&gt;::registerFactory(const Key &amp;key, const FactoryFunc factory)
{
    m_map[key] = factory;
}

template&lt;typename Base,
        typename Key,
        typename... Args&gt;
std::unique_ptr&lt;Base&gt; Registry&lt;Base, Key, Args...&gt;::construct(const Key &amp;key, Args... args)
{
    try{
        return m_map.at(key)(std::forward&lt;Args&gt;(args)...);
    }
    catch(const std::out_of_range &amp;e)
    {
        throw ConstrError(key);
    }
}

template&lt;typename Base,
        typename Key,
        typename... Args&gt;
template&lt;typename Derived&gt;
std::unique_ptr&lt;Base&gt; Registry&lt;Base, Key, Args...&gt;::constructDerived(Args... args)
{
    return std::make_unique&lt;Derived&gt;(std::forward&lt;Args&gt;(args)...);
}
Good stuff!

I definitely see a few improvements you could make here:

Prefer using std::function to function pointers

There is a tiny bit more overhead invovled, but the extra flexibility is well worth it.

using FactoryFunc = std::function&lt;std::unique_ptr&lt;Base&gt;(Args...)&gt;;


Another advantage is that it lets you get rid of constructDerived entirely, and replace it with a nice lambda in registerClass.

Nitpick: registerClass should invoke registerFactory.

Since registerClass is just a specialization of registerFactory, it should invoke it instead of reimplementing it. This is preferable because having a single point of entry makes refactorings like adding logging or debug monitoring a lot less error-prone.

Prefer using instead of typedef

The semantics of type alisases are just a lot more legible that way.

Wrong function definition for forwarding args

If you want to use forwarding as you do, construct needs to be declared in a way to use universal references, like so:

template&lt;typename... CtrArgs&gt;
std::unique_ptr&lt;Base&gt; construct(const Key &amp;key, CtrArgs&amp;&amp;... args)


Otherwise, your std::forward&lt;&gt; call is useless and might as well be a std::move.

Personal opinion: The custom exception type is not necessary here.

Letting the out_of_range exception bubble up is perfectly acceptable here, and lets your code be cleaner.