c++factory-pattern

factory method for multiple constructors in the same class


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 signboolean. Is there a way to fix the code in order to register multiple create functions for the the same class?

Best regards


Solution

  • 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.

    Demo