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 <unordered_map>
#include <memory>
template<typename Key>
class RegistryConstructionError : public std::exception
{
public:
RegistryConstructionError(const Key &key) :key(key){}
const char *what()const throw(){return "Undefined key";}
const Key key;
};
template<typename Base, typename Key, typename... Args>
class Registry
{
public:
typedef std::unique_ptr<Base> (*FactoryFunc)(Args... args);
Registry() = default;
~Registry() = default;
template<typename Derived>
void registerClass(const Key &key);
void registerFactory(const Key &key, const FactoryFunc factory);
std::unique_ptr<Base> construct(const Key &key, Args... args);
private:
template<typename Derived>
static std::unique_ptr<Base> constructDerived(Args... args);
std::unordered_map<Key, FactoryFunc> m_map;
public:
typedef RegistryConstructionError<Key> ConstrError;
};
#include "registry.tpp"
#endif // REGISTRY_HPP
registry.tpp:
template<typename Base,
typename Key,
typename... Args>
template<typename Derived>
void Registry<Base, Key, Args...>::registerClass(const Key &key)
{
m_map[key] = &constructDerived<Derived>;
}
template<typename Base,
typename Key,
typename... Args>
void Registry<Base, Key, Args...>::registerFactory(const Key &key, const FactoryFunc factory)
{
m_map[key] = factory;
}
template<typename Base,
typename Key,
typename... Args>
std::unique_ptr<Base> Registry<Base, Key, Args...>::construct(const Key &key, Args... args)
{
try{
return m_map.at(key)(std::forward<Args>(args)...);
}
catch(const std::out_of_range &e)
{
throw ConstrError(key);
}
}
template<typename Base,
typename Key,
typename... Args>
template<typename Derived>
std::unique_ptr<Base> Registry<Base, Key, Args...>::constructDerived(Args... args)
{
return std::make_unique<Derived>(std::forward<Args>(args)...);
}