I have built an auto registration framework for a plugin system using CRTP, which works fine. The issue came when I wanted to have an inheritance history with it. My original plan was to accumulate a vector of the parent ids as the classes auto registered themselves. My attempt is in the code below and as it is rather long I put it at the end of the question.
The InterfaceFactory and the AutoRegister classes work fine through CRTP (even though AutoRegister functionality is inherited multiple times). The system is able to create the correct type based on the id provided and all of the registration functionality is built by the compiler at compile time.
My thought to add the inheritance history was to add the inheritance up as they were registered, it seemed simple enough. I planned to use the static "InterfaceType s_type" during registration to get the INTERFACE class's information and add to the current. The issue was that the original INTERFACE call "BaseInterface" (and ones like it) do not have the s_type. Next thought was to use SFINAE to ignore those classes in the hierarchy (as it did not have an id anyways). This brought about the BaseId structs in the AutoRegister, which attempted to key off s_type. This however does not seem to work as the specialization is never used. I am assuming Base::BaseId is created using the non-specialized one as there is no BaseInterface::s_type and when Derived is registered (since it is derived from Base) the compiler is picking up the Base::BaseId and not even attempting the specialization. So my questions are, is this assumption true? and if so could someone explain a little because I am hazy on the details and is there another way to accomplish this?
#include <vector>
#include <functional>
template <typename T> struct TypeName
{
static std::string get()
{
std::string fullName=typeid(T).name();
size_t beginPos=0;
size_t classPos=fullName.find("class");
size_t nameSpacePos=fullName.find_last_of("::");
if(classPos != std::string::npos)
beginPos=classPos+6;
if(nameSpacePos != std::string::npos)
{
if(nameSpacePos+1 > beginPos)
beginPos=nameSpacePos+1;
}
return fullName.substr(beginPos);
}
};
class BaseInterface
{
public:
BaseInterface() {}
virtual ~BaseInterface() {}
};
struct InterfaceType
{
InterfaceType():id(-1){}
unsigned int id;
std::vector<unsigned int> idInheritance;
std::string name;
};
template<typename CLASS, typename INTERFACE>
class AutoRegister:public INTERFACE
{
public:
AutoRegister():INTERFACE() { &s_type; }
static BaseInterface *create(unsigned int type) { CLASS *newClass=new CLASS(); return newClass; }
template<typename T, typename=int>
struct BaseId
{
static std::vector<unsigned int> get() { return std::vector<unsigned int>(); }
};
template<typename T>
struct BaseId<T, decltype((void)T::s_type, 0)>
{
static std::vector<unsigned int> get()
{
std::vector<unsigned int> ids;
ids.push_back(T::s_type.id); ids.insert(ids.end(), T::s_type.idInheritance.begin(), T::s_type.idInheritance.end());
return ids;
}
};
static std::vector<unsigned int> getBaseIds() { return BaseId<INTERFACE>::get(); }
private:
static InterfaceType s_type;
};
class InterfaceFactory
{
public:
typedef BaseInterface *(*FactoryFunc)(unsigned int type);
class BaseInterfaceNode
{
public:
BaseInterfaceNode(unsigned int type, std::string typeName, FactoryFunc factoryFunction):
m_type(type), m_typeName(typeName), m_factoryFunction(factoryFunction)
{};
size_t type() { return m_type; }
std::string typeName() { return m_typeName; }
BaseInterface *factoryFunction() { return m_factoryFunction(m_type); }
private:
unsigned int m_type;
std::string m_typeName;
FactoryFunc m_factoryFunction;
};
typedef std::vector<BaseInterfaceNode> BaseInterfaceNodes;
public:
InterfaceFactory() {}
~InterfaceFactory() {}
public:
static BaseInterface *createType(unsigned int type);
static InterfaceType registerType(std::string typeName, std::vector<unsigned int> ids, FactoryFunc factoryFunc);
struct BaseInterfaceNodeHolder
{
BaseInterfaceNodeHolder():s_interfaceTypeIndex(0) {}
BaseInterfaceNodes s_baseInterfaceNodes;
unsigned int s_interfaceTypeIndex;
};
private:
};
template<typename CLASS, typename INTERFACE> InterfaceType AutoRegister<CLASS, INTERFACE>::s_type=\
InterfaceFactory::registerType(TypeName<CLASS>::get(), AutoRegister<CLASS, INTERFACE>::getBaseIds(), &AutoRegister<CLASS, INTERFACE>::create);
InterfaceFactory::BaseInterfaceNodeHolder *s_nodes=nullptr;
InterfaceType InterfaceFactory::registerType(std::string typeName, std::vector<unsigned int> ids, FactoryFunc factoryFunc)
{
if(s_nodes == nullptr)
s_nodes=new BaseInterfaceNodeHolder();
InterfaceType sampleType;
sampleType.id=s_nodes->s_interfaceTypeIndex;
sampleType.idInheritance=ids;
sampleType.name=typeName;
s_nodes->s_baseInterfaceNodes.push_back(BaseInterfaceNode(s_nodes->s_interfaceTypeIndex, typeName, factoryFunc));
s_nodes->s_interfaceTypeIndex++;
return sampleType;
}
//////////////////////////////////////////////////////////////////////
class Base:public AutoRegister<Base, BaseInterface>
{
};
class Derived:public AutoRegister<Derived, Base>
{
};
int main(int argc, const char* argv[])
{
Base base;
Derived derived;
return 0;
}
Thanks,