Skip to content

Instantly share code, notes, and snippets.

@eyalroz
Last active June 3, 2016 21:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eyalroz/832836d8c005ec58db76ce7c7b745fdc to your computer and use it in GitHub Desktop.
Save eyalroz/832836d8c005ec58db76ce7c7b745fdc to your computer and use it in GitHub Desktop.
/**
* Implementation of the factory pattern, based on suggestions here:
*
* http://stackoverflow.com/q/5120768/1593077
*
* and on the suggestions for corrections here:
*
* http://stackoverflow.com/a/34948111/1593077
*
*/
#pragma once
#ifndef UTIL_FACTORY_H_
#define UTIL_FACTORY_H_
#include <unordered_map>
#include <exception>
namespace util {
#ifndef UTIL_EXCEPTION_H_
using std::logic_error;
#endif
template<typename Key, typename T, typename... ConstructionArgs>
class Factory {
public:
using Instantiator = T* (*)(ConstructionArgs...);
protected:
template<typename U>
static T* createInstance(ConstructionArgs... args)
{
return new U(std::forward<ConstructionArgs>(args)...);
}
using Instantiators = std::unordered_map<Key,Instantiator>;
Instantiators subclassInstantiators;
public:
template<typename U>
void registerClass(const Key& key)
{
// TODO: - Consider repeat-registration behavior.
static_assert(std::is_base_of<T, U>::value,
"This factory cannot register a class which is is not actually "
"derived from the factory's associated class");
auto it = subclassInstantiators.find(key);
if (it != subclassInstantiators.end()) {
throw logic_error("Repeat registration of the same subclass in this factory.");
}
subclassInstantiators.emplace(key, &createInstance<U>);
}
public:
// TODO: Consider throwing on failure to find the instantiator
T* produce(const Key& subclass_key, ConstructionArgs... args) const
{
auto it = subclassInstantiators.find(subclass_key);
if (it == subclassInstantiators.end()) {
return nullptr;
}
auto instantiator = it->second;
return instantiator(std::forward<ConstructionArgs>(args)...);
}
bool canProduce(const Key& subclass_key) const {
return subclassInstantiators.find(subclass_key) != subclassInstantiators.end();
}
};
} // namespace util
#endif /* UTIL_FACTORY_H_ */
#include "Factory.h"
#include <string>
struct Foo
{
Foo(int x) { };
};
int main()
{
util::Factory<std::string, Foo, int> factory;
factory.registerClass<Foo>("foo");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment