c++ - 注册一个 C++ 类,以便稍后一个函数可以遍历所有已注册的类

标签 c++ metaprogramming registration boost-preprocessor

我正在尝试编写一个在运行时动态加载其扩展的应用程序。我使用 Boost 预处理器库编写了一个预处理器函数,给定一个名称列表,为每个名称声明一个类(并使它们成为某个 AbstractPlugin 类的子类),然后声明一个包含这些类的 Boost MPL 序列。然后我写了一个类,如果它可以转换为该 MPL 序列中的任何类型,它会尝试指向 AbstractPlugin 的指针。 这里的问题是我的预处理器函数需要我想要创建和加载的所有扩展的完整列表。是否有某种技术可以让我在单独的文件中注册每个扩展?

更新:

我认为,我对情况的解释过于模糊,所以我决定更具体一些。

我想定义一个扩展类型的集合。对于每种扩展类型,可以有任意数量的扩展。在运行时,程序加载外部库,解析入口点函数,调用它,结果得到一个指针。然后它尝试将该指针转换为所有已注册的扩展类型(使用 dynamic_cast,因此扩展类型的类都继承自某个多态基类)。如果对某些扩展类型的转换成功,则转换后的指针将用于调用该扩展类型的特殊处理程序。

扩展类型的数量在编译时是已知的(而显然,扩展的数量是无限的)。使用我的方法,加载程序类使用此知识来检查是否存在每个扩展类型的处理程序(如果不存在,则程序不会编译)。此外,我的方法不会强制扩展类型的类知道加载程序的任何信息(因此很容易修改加载程序)。但是如果每个扩展类型都自己注册会更方便。

最佳答案

您可以让您的所有类在某种集合中自行注册。这是一个框架方法:

基础.hpp:

#include <memory>
#include <unordered_map>
#include <string>

struct Base
{
    virtual ~Base() = default;

    using create_f = std::unique_ptr<Base>();

    static void registrate(std::string const & name, create_f * fp)
    {
        registry()[name] = fp;
    }

    static std::unique_ptr<Base> instantiate(std::string const & name)
    {
        auto it = registry().find(name);
        return it == registry().end() ? nullptr : (it->second)();
    }

    template <typename D>
    struct Registrar
    {
        explicit Registrar(std::string const & name)
        {
            Base::registrate(name, &D::create);
        }
        // make non-copyable, etc.
    };

private:
    static std::unordered_map<std::string, create_f *> & registry();
};

基础.cpp:

#include "Base.hpp"

std::unordered_map<std::string, Base::create_f *> & Base::registry()
{
    static std::unordered_map<std::string, Base::create_f *> impl;
    return impl;
}

现在在客户端中使用它:

Derived.hpp:

#include "Base.hpp"

struct Derived : Base
{
    static std::unique_ptr<Base> create() { return std::make_unique<Derived>(); }
    // ...
};

Derived.cpp:

#include "Derived.hpp"

namespace
{
    Base::Registrar<Derived> registrar("MyClass");
}

Base::Registrar<Derived> 的构造函数负责注册类(class) Derived名下"MyClass" .您可以创建 Derived 的实例动态通过:

std::unique_ptr<Base> p = Base::instantiate("MyClass");

可以/应该通过检测重复注册、打印可用类列表等来改进代码。请注意我们如何避免任何静态初始化排序问题,我将实际的注册表映射对象设为 block 静态对象,这保证了在首次使用前进行初始化,因此仅在最后一次使用后销毁。

关于c++ - 注册一个 C++ 类,以便稍后一个函数可以遍历所有已注册的类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11175379/

相关文章:

c++ - C++ : Compile Error: expected initializer before ‘<’ token

java - 在 JAX-RS 应用程序中手动注册资源类有什么好处?

image - 在Matlab中应用变换后如何保持初始图像大小?

C++类型特征提取模板参数类

metaprogramming - Elixir - 通过元编程在模块中定义函数

c# - 在为 ASP.NET MVC 2.0 应用程序注册区域时提供或过滤程序集

c++ - LNK1104 无法打开文件 'legacy_stdio_definitions.lib'

c++ - 如何保留 C++ 流的格式?

c++ - 将字符串设置为 QDoubleSpinBox

macros - Elixir:在定义它的同一模块的主体中​​使用宏