The problem
I want to make a little module system for my project, which will basically be a base class that users may extend with their code, include in the main project and be able to use this module in runtime.
E.g. we have a Renderer module, the base class defines all the mandatory functions to implement:
class Renderer
{
public:
virtual void BeginFrame(
/* all the possible parameters: cameras, scene metadata, etc. */) = 0;
virtual void Draw(uint32_t vertexCount,
uint32_t firstVertex,
uint32_t instanceCount = 1,
uint32_t firstInstance = 0) = 0;
// All the other overloads for different draw metadata
// ...
virtual void EndFrame() = 0;
};
Now I try to implement these function in Vulkan Renderer module - implementation doesn't matter here. What I want to do is to have some global storage for modules (seems unordered_map is a way to go), where you have a module identifier (probably a string which names the module) and function which creates this module and returns unique_ptr of base Renderer class to use in the client application.
What I've tried
Right now I define an extern unordered_map in my Renderer.hpp
and the idea is to insert module metadata (identifier and a function to create one) into this map.
//
// Renderer.hpp
//
using RendererModuleCreator = std::function<std::unique_ptr<Renderer>()>;
// Append your custom renderer module here with key being any string you would
// like to name your module.
extern std::unordered_map<std::string, RendererModuleCreator> s_RendererModules;
//
// VulkanRenderer.hpp
//
// Somewhere in the header file
void*
AppendVkRenderer()
{
s_RendererModules.insert(
{ "VkRenderer", []() { return std::make_unique<VulkanRenderer>(); } });
return nullptr;
}
//
// VulkanRenderer.cpp
//
// As global variable, should execute the function and append the module to global store.
void* appendCall = AppendVkRenderer();
The above solution only works if you somehow reference VulkanRenderer in compilation units for client application. Otherwise, the code doesn't get executed even if the header file is included. If I try to declare appendCall
in the header, I face linker errors because of symbol redefinition.
Is there a way to make this system work?
CodePudding user response:
If you are using C 17 you could use a static inline (otherwise useless) member variable in some class to make sure the function is called, e.g. like this:
class Foo {
static inline void * bar_ = AppendVkRenderer();
};
But you might have to modify parts of your code to make sure s_RendererModules
is initialized before AppendVkRenderer
is called.