有没有一种方法可以在编译时从C++文件附加到全局无序映射



问题

我想为我的项目制作一个小模块系统,它基本上是一个基类,用户可以用他们的代码扩展,包括在主项目中,并能够在运行时使用这个模块。

例如,我们有一个Renderer模块,基类定义了要实现的所有强制函数:

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;
};

现在我尝试在Vulkan Renderer模块中实现这些函数——在这里实现并不重要。我想做的是为模块提供一些全局存储(似乎有一种方法可以实现(,其中有一个模块标识符(可能是一个命名模块的字符串(和创建该模块并返回基础Renderer类的unique_ptr以在客户端应用程序中使用的函数。

我尝试过的

现在,我在Renderer.hpp中定义了一个外部的Undered_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();

只有当您以某种方式在客户端应用程序的编译单元中引用VulkanRenderer时,上述解决方案才有效。否则,即使包含头文件,代码也不会执行。如果我试图在标头中声明appendCall,由于符号重新定义,我将面临链接器错误。

有没有办法让这个系统发挥作用?

如果您使用C++17,您可以在某个类中使用静态内联(否则将毫无用处(成员变量来确保函数被调用,例如:

class Foo {
static inline void * bar_ = AppendVkRenderer();
};

但是,您可能需要修改部分代码,以确保在调用AppendVkRenderer之前初始化了s_RendererModules

最新更新