Factory Design Pattern (device)

Hi,

Does anyone have ideas on how to implement the factory design pattern on the device side? For host side you would normally use a macro to automatically register each class with the singleton factory class. However, you then have a structure with references to the constructors of classes which I presume are invalid references if you tried to copy them across to the device.

Has anyone got a suggestion on how to proceed? Is the approach to use a standard factory singleton pattern with automatic registration on the host side and then write a routine that brings the references across to the device? Appreciate any ideas anyone has. My current approach is not exactly nice:

#include … all my classes

CUDA_CALLABLE_MEMBER Baseclass* ComponentFactory::CreateInstance(ClassType classType)
{
Baseclass* instance = nullptr;
switch (classType)
{

all the classes

}
}

just do everything on the device, including instantiation of the singleton class

I would like to do this. What I am struggling with is how to automatically register my classes with the singleton on the device. The macro for registration gets executed as soon as the host code runs. I can post an example of the factory class I am using if this helps. Maybe there is a way of asking the compiler to make a macro execute on the device only.

To be a bit more precise, I am using the following approach to register classes with the factory.

The code for the factory and a helper class for registering is below:

// A preprocessor define used by derived classes
#define REGISTER_CLASS(NAME, TYPE) static Registrar registrar(NAME, [](void) -> MyBaseClass * { return new TYPE();});

// The factory - implements singleton pattern!
class MyFactory
{
public:
    // Get the single instance of the factory
    static MyFactory * Instance()
	{
		static MyFactory factory;
		return &factory;
	};

    // register a factory function to create an instance of className
	void RegisterFactoryFunction(string name, function<MyBaseClass*(void)> classFactoryFunction)
	{
		// register the class factory function 
		factoryFunctionRegistry[name] = classFactoryFunction;
	}


    // create an instance of a registered class
    MyBaseClass* Create(string name)
	{
		MyBaseClass * instance = nullptr;

		// find name in the registry and call factory method.
		auto it = factoryFunctionRegistry.find(name);
		if (it != factoryFunctionRegistry.end())
			instance = it->second();

		// wrap instance in a shared ptr and return
		if (instance != nullptr)
			//return std::shared_ptr<MyBaseClass>(instance);
			return instance;
		else
			return nullptr;
	}

private:
    // a private ctor
    MyFactory(){}

    // the registry of factory functions
    map<string, function<MyBaseClass*(void)>> factoryFunctionRegistry;

};

// A helper class to register a factory function
class Registrar {
public:
	Registrar(string name, function<MyBaseClass*(void)> classFactoryFunction)
	{
		// register the class factory function
		MyFactory::Instance()->RegisterFactoryFunction(name, classFactoryFunction);
	}
};

Then in each class I want to be registered, I would put:

REGISTER_CLASS("DerivedClass", DerivedClass);

straight after the #include’s for the cpp file (this creates a static instance of the Registrar class with parameters equal to the class name and a lambda to the class constructor.

The constructor for the Registrar class get’s executed as soon as the host code is launched which is fine for a host factory, but I need these static Registrar classes to only be constructed on the device. Any thoughts on how this might be achieved?

Also note that you cannot do the registration using the above approach from device in the same way - e.g. if you change the macro to:

#define REGISTER_CLASS(NAME, TYPE) device static Registrar registrar(NAME, -> MyBaseClass * { return new TYPE();});

then you get the error “dynamic initialization is not supported for device, constant and shared variables”.