dimanche 23 avril 2023

Factory method does not work when used in dynamic library with templated classes [duplicate]

I have created a templated class where I would like to use the factory method. The templates should be explicitly defined to create objects of type int, double and bool.

The factory has a checkIn registry mechanism through the use of the a static bool.

The factory is defined as:

#ifndef Factory_H
#define Factory_H

#include <memory> 
#include <map>

template<class Type> 
class Base;

template<class Type> 
class Factory
{
    public:
        using createObj = std::shared_ptr<Base<Type>>(*)();

        static bool registerObj( const std::string& name, createObj type)
        {
            std::map< std::string, Factory::createObj >& registry = getRegistry();

            if(registry.find(name) == registry.end())
            { 
                registry[name] = type;
                return true;
            }
            return false;
        };

        static std::shared_ptr<Base<Type>> New( const std::string& name)
        {
            auto it = getRegistry().find(name);
            if (it == getRegistry().end()) {
                return nullptr;
            }
            return it->second();
        };
        
    private:
        static std::map<std::string, createObj>& getRegistry()
        {
            static std::map<std::string, Factory::createObj> registry;
            return registry;
        };        
};

#endif

The base class is defined as:

#ifndef Base_H
#define Base_H

#include "factory.h"

template<class Type>
class Base: public Factory<Type>
{
    public:
        Base();
        virtual void foo() = 0;
};

#endif

and implemented as:

#include "Base.h"
#include <iostream>

template <class Type>
Base<Type>::Base()
{}

// Explicit initalization
template class Base<int>;
template class Base<double>;
template class Base<bool>;

The derived class is defined as:

#ifndef Derived_H
#define Derived_H

#include "Base.h"

template<class Type>
class Derived: public Base<Type>
{
    private:
        static bool checkIn_;
        static std::string className_;

    public:
        Derived();
        virtual void foo() ;
        static std::shared_ptr<Base<Type>> Create();

};
#endif

and implemented as:

#include "Derived.h"

template<class Type>
Derived<Type>::Derived()
{}

template<class Type>
std::string Derived<Type>::className_("Derived");

template<class Type>
std::shared_ptr<Base<Type>> Derived<Type>::Create()
{
    return std::make_shared<Derived>();
}


template<class Type>
bool Derived<Type>::checkIn_ = Base<Type>::registerObj(Derived::className_, Derived::Create);

template<class Type>
void Derived<Type>::foo()
{
    std::cout << typeid(Type).name() << std::endl;
}

// Explicit initalization
template class Derived<int>;
template class Derived<double>;
template class Derived<bool>;

The main.cpp is defined as:

#include<iostream>
#include "Derived.h"
#include "Base.h"

int main()
{
    auto obj1 = Base<int>::New("Derived");
    auto obj2 = Base<double>::New("Derived");
    auto obj3 = Base<bool>::New("Derived");

    obj1->foo();
    obj2->foo();
    obj3->foo();

    return 0;
}

If I compile everything in one executable: g++ -g *.cpp -o main. The factory method works.

If I try to compile it as a library; g++ -g -fPIC Base.cpp Derived.cpp -shared -o test.so followed by g++ -g -o main main.cpp -I . -L. test.so it no longer works. There is nothing in the registry... I would guess the static bool is not doing its job.

How can I make this work?

Aucun commentaire:

Enregistrer un commentaire