注册一个C++类,以便函数稍后可以循环访问所有已注册的类

Register a C++ class so that later a function can iterate over all registered classes

本文关键字:注册 循环 访问 一个 C++ 函数      更新时间:2023-10-16

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

更新:

我相信,我对情况的解释太模糊了,所以我决定更具体。

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

扩展

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

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

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

现在要在客户端中使用它:

派生.hpp:

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

派生.cpp:

#include "Derived.hpp"
namespace
{
    Base::Registrar<Derived> registrar("MyClass");
}

Base::Registrar<Derived>的构造函数负责在名称 "MyClass" 下注册类Derived。您可以通过以下方式动态创建Derived实例:

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

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

使用抽象工厂模式实现这样的扩展框架并不难。

http://en.wikipedia.org/wiki/Abstract_factory_pattern

您可以在全局列表中注册这些抽象的工厂函数/对象,并基于它执行任何您想做的事情。

事实证明,

我想要的是不可能的。原因是在此上下文中"寄存器"意味着"将类型放入类型序列中",并且类型序列是不可变的,因为它们本身就是类型。因此,应该手动创建此类型序列,或者按照某些人的建议将"注册"移动到运行时。