在编译时生成某种子类/类型注册表?

时间:2018-08-14 20:06:58

标签: c++

我正在编写一个具有多个父类子类的应用程序(游戏),这些子类都需要在地图中注册,以便可以在运行时读取的文件中引用它们。

例如,如果我有一个Subclass类,并且我的文件指定它需要一个"Subclass"的实例,那么我的文件解析器将在此映射中查找值,即{ {1}}初始化子类的实例,并将其作为父类指针返回。

我目前是通过std::function文件来完成此操作的,在该文件中,我必须手动输入每个新类,如下所示:

registry.cpp

我注意到具有类似设置的其他应用程序似乎能够使用宏(例如Valve Software's Source Engine, which uses a DECLARE_CLASS macro in the class's cpp file, with no need for a header file or any other configuration whatsoever)自动注册这些子类。

如何在自己的应用程序中完成这种零配置的“子类注册表”?

2 个答案:

答案 0 :(得分:2)

这些宏基本上声明了一个文件作用域变量(在标识符中包括类名,以使它们唯一)。该变量的构造函数调用一个函数来注册lambda。

例如像这样:

std::map<std::string, std::function<Parent*()>>  actions;
class RegisterClass
{
    public:
        RegisterClass(std::string const& className, std::function<Parent*()>&& action)
        {
            actions.insert(std::make_pair(className, std::move(action)));
        }
};
#define REGISTERCLASS(Class)              \
    static RegisterClass   tmpMyUniqueName ## Class( # Class,  [](){return new Class;})

                                    //               ^ Single # quotes the identifier
                                    //     ^^ Double ## combines the pre and post identifiers.

如果您将以上内容与以下内容一起使用:

class X: public Parent {};
class Y: public Parent {};
REGISTERCLASS(X);
REGISTERCLASS(Y);

您将获得:

class X: public Parent {};
class Y: public Parent {};
static RegisterClass tmpMyUniqueNameX( "X", [](){return new X;});
static RegisterClass tmpMyUniqueNameY( "Y", [](){return new Y;});

答案 1 :(得分:0)

当前实现的基础基本上是您想要的方法。您有一个ID字符串映射到默认构造函数。可以将其模板化以使语法更好(请参见出色的答案http://stackoverflow.com/a/1809715/571778

一旦有了,您就可以在某处保留此注册映射的static副本,然后编写一个宏来进行注册。这就是折衷方案。在我正在开发的游戏上,我会根据是加载编辑器还是普通游戏引擎来实例化不同的实现,因此在我的用例中,能够在运行时替换不同的注册是优于静态注册的优势。