mercredi 2 mai 2018

Object Factory registration of template class hierarchy

I implemented a general object factory following the guidelines of Andrei Alexandrescu's book Modern C++ Design, so I can define a class hierarchy like this (I will write the code in the most simplified way, avoiding implementation details or memory allocation/deallocation issues; I'm aware of these things and I would like to focus the discussion on the main issue):

// File "base.h"
#include <string>
#include "singleton.h"
#include "object_factory.h"
class Base;

using SingletonBaseFactory = Singleton
<
     ObjectFactory
     <
         Base,         // Abstract product type
         std::string,  // Identifier type
         Base* (*)()   // Concrete product creator type
     >
>;

class Base {
    // Define the interface (virtual functions, virtual dtor)
public:
    // Wrap the Factory method
    static Base* Factory(const std::string& ID) {
        return SingletonBaseFactory::Instance().Factory(ID);
    }
};

// File "derived_1.h"
#include "base.h"
class Derived_1 : public Base { /* ... */ };

// File "derived_2.h"
#include "base.h"
class Derived_2 : public Base { /* ... */ };

and register each derived class within an anonymous namespace in the corresponding implementation file:

// File "derived_1.cpp"
#include "derived_1.h"
namespace {
    Base* CreateDerived_1() {
        return new Derived_1;
    }

    const bool registered = SingletonBaseFactory::Instance().Register("Derived_1", CreateDerived_1);
}

// Same for Derived_2 in file "derived_2.cpp"

Therefore, an user that wants to use this hierarchy in his code has just to invoke the Base::Factory method with a proper identifier:

// File main.cpp
#include"base.h"
int main(){
    Base* pb = Base::Factory("Derived_1");

    // Do stuff with pb

    return 0;
}

Now, suppose I have a template class hierarchy, say:

// File "baset.h"
#include <string>
#include "singleton.h"
#include "object_factory.h"

template<class T>
class BaseT;

template<class T>
using SingletonBaseTFactory = Singleton
<
    ObjectFactory
    <
        BaseT<T>,         // Abstract product type
        std::string,      // Identifier type
        BaseT<T>* (*)()   // Concrete product creator type
    >
>;

template<class T>
class BaseT {
    /*Define the interface*/ 
public:
    BaseT Factory(const std::string& ID) {
        return SingletonBaseTFactory<T>::Instance().Factory(ID);
    }
};

// File "derivedt_1.h"
#include "baset.h"
template<class T>
class DerivedT_1 : public BaseT<T> { /* ... */ };

In this case the registration is an user responsibility for each type T he wants to use, before using the class hierarchy:

// File main.cpp
#include "baset.h"
#include "derivedt_1.h"

bool register_derived_1_int = SingletonBaseTFactory<int>::Instance().Register("Derived_1", [](){ return new DerivedT_1<int>; });

int main() {
    BaseT<int>* pb = BaseT<int>::Factory();
    return 0;
}

Keeping in mind that the ID of each derived template class is the same for every type T, would it make sense to delegate the registration responsibility to the developer of each derived class (rather than the user) even in the templated case? If so, is there a workaround to achieve it?

Aucun commentaire:

Enregistrer un commentaire