lundi 23 août 2021

In C++, Is there a way to define template behavior based on whether the input class is abstract?

Background: I've inherited a large system that makes use of templates to store meta data about classes, that may have colored some of the assumptions inherent in this question.

I'm making use of a template registration system that is partially based on an answer found here: Is there a way to instantiate objects from a string holding their class name? . Macros are a no go in my system, as is the use of boost (or really any third party API).

Question: Can I have templates that behave differently based on whether the input type is abstract versus concrete?

I'm looking for something like this (Code used here directly copied from the accepted answer in the linked question):

struct BaseFactory {
    typedef std::map<std::string, Base*(*)()> map_type;

    static Base * createInstance(std::string const& s) {
        map_type::iterator it = getMap()->find(s);
        if(it == getMap()->end())
            return 0;
        return it->second();
    }
protected:
    static map_type * getMap() {
        // never delete'ed. (exist until program termination)
        // because we can't guarantee correct destruction order 
        if(!map) { map = new map_type; } 
        return map; 
    }

private:
    static map_type * map;
};

template<typename T>
struct DerivedRegister : BaseFactory { 
    DerivedRegister(std::string const& s) { 
        getMap()->insert(std::make_pair(s, &createT<T>));
    }
};

// in derivedb.hpp
class DerivedB {
    ...;
private:
    static DerivedRegister<DerivedB> reg;
};

// in derivedb.cpp:
DerivedRegister<DerivedB> DerivedB::reg("DerivedB");

Except that I would like DerivedRegister to behave differently based on whether T is abstract versus concrete. In the case where T is abstract, I would expect DerivedRegister to not register the type with the map.

As I mentioned in the background, I've already inherited an existing system which already exists on the class hierarchy (abstract or concrete). It was trivial to modify this existing system to add the map registration; however, the abstract classes are causing problems since calling new on them isn't valid.

Adding additional layers of inheritance and templating between BaseFactory and DerivedRegister wouldn't be a problem; however, DerivedRegister already exists on every class and I can't change that.

I recognize that I could just add a unique registration system independent of the existing template classes and only add it to the concrete classes. I'm specifically asking if there is a solution where I can avoid that in C++11 without using third party libraries (lots of restrictions I know...).

Aucun commentaire:

Enregistrer un commentaire