I have this code for a factory design pattern that will take into account any number of arguments in the constructor. Through a static
boolean in the class a certain constructor is registered in the factory
. However it requires reinterpret_cast
to run. Also the boolean strategy is not very elegant (it works, but If I have 4 constructors I will have to have 4 booleans to perform the registry).
I would like to have a robust approach to register the appropriate constructor.
How can I improve the code?
#include <unordered_map>
#include <string>
#include <iostream>
#include <memory>
class Base;
class myFactory
{
public:
typedef std::unordered_map<std::string, void*(*)()> registry_map;
virtual ~myFactory() = default;
static registry_map & registry()
{
static registry_map impl;
return impl;
}
template<typename ...Ts>
static std::shared_ptr<Base> instantiate(std::string const & name, const Ts&...args)
{
auto it = registry().find(name);
if ( it == registry().end()) return nullptr;
typedef std::shared_ptr<Base> (*create_type)(Ts...);
auto create_fun = reinterpret_cast<create_type>(it->second);
return create_fun(args...);
}
template<typename F>
static bool sign(const std::string& name, F* func)
{
registry()[name] = reinterpret_cast<void*(*)()>(func);
return true;
}
};
class Base: public myFactory
{
public:
Base(int a):var1(a){}
Base(int a, int b):var1(a+b){}
virtual ~Base() = default;
virtual void f() = 0;
int var(){return var1;}
private:
int var1;
};
class DerivedExample : public Base
{
private:
static bool sign1;
static bool sign2;
public:
DerivedExample(int a):Base(a){std::cout << var()<< std::endl;}
DerivedExample(int a, int b):Base(a,b){std::cout << a << b << std::endl;}
static std::shared_ptr<Base> create(int a) { return std::make_shared<DerivedExample>(a);}
static std::shared_ptr<Base> create(int a, int b) { return std::make_shared<DerivedExample>(a,b);}
virtual void f() override { std::cout << "DerivedExample" << std::endl; }
};
bool DerivedExample::sign1 = DerivedExample::myFactory::sign("DerivedExample1", static_cast<std::shared_ptr<Base> (*)(int)>(&DerivedExample::create));
bool DerivedExample::sign2 = DerivedExample::myFactory::sign("DerivedExample1", static_cast<std::shared_ptr<Base> (*)(int, int)>(&DerivedExample::create));
int main()
{
std::shared_ptr<Base> p1 = Base::instantiate("DerivedExample1", 10);
std::shared_ptr<Base> p2 = Base::instantiate("DerivedExample1", 1, 2);
p1->f();
p2->f();
return 0;
}
Kind regards
std::make_unique
, from the Standard Library. It accepts any and all valid constructor arguments, and you can assign it to astd::shared_ptr
, or any kind of smart pointer to a base-class interface for polymorphism. Without more information, I can’t tell you if that meets your requirements, but you should always start by asking if it does. \$\endgroup\$std::shared_ptr<Base> polymorphic = std::make_unique<Derived>(foo, bar);
Orstd::make_shared
would work too. \$\endgroup\$