I have this code which is an adaptation from How to pass arguments to factory elements constructors? to work with smart pointers.
#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 ...T>
static std::shared_ptr<Base> instantiate(std::string const & name, T&&...args)
{
auto it = registry().find(name);
if ( it == registry().end()) return 0;
typedef std::shared_ptr<Base> (*create_type)(T...);
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:
virtual void f() = 0;
virtual ~Base() = default;
};
class DerivedExample : public Base
{
private:
static bool sign;
public:
DerivedExample(int a, int b){std::cout << a << b << std::endl;}
DerivedExample() = default;
static std::shared_ptr<Base> create() { return std::make_shared<DerivedExample>();}
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::sign = DerivedExample::myFactory::sign("DerivedExample", DerivedExample::create());
bool DerivedExample::sign = DerivedExample::myFactory::sign("DerivedExample", DerivedExample::create(int a, int b)); // redefinition
int main()
{
std::shared_ptr<Base> p1 = Base::instantiate("DerivedExample");
std::shared_ptr<Base> p2 = Base::instantiate("DerivedExample", 1, 2);
p1->f();
p2->f();
}
This implementation does not let me register 2 constructors for the factory because of a redefinition of sign
boolean. Is there a way to fix the code in order to register multiple create
functions for the the same class?
Best regards
The bool sign
is used for "auto" registration at global scope. You might just add extra variable:
class DerivedExample : public Base
{
private:
static bool sign1;
static bool sign2;
// ...
};
bool DerivedExample::sign1 = DerivedExample::myFactory::sign("DerivedExample1", static_cast<std::shared_ptr<Base> (*)()>(&DerivedExample::create));
bool DerivedExample::sign2 = DerivedExample::myFactory::sign("DerivedExample2", static_cast<std::shared_ptr<Base> (*)(int, int)>(&DerivedExample::create));
The way to register was wrong BTW, especially when overloads are involved.