我正在尝试编写一个在运行时动态加载其扩展的应用程序。我使用Boost预处理器库来编写预处理器函数,给定一个名称列表,为每个名称声明一个类(并使所有这些类成为某些AbstractPlugin类的子类),然后声明包含这些类的Boost MPL序列。然后我编写了一个类,它尝试指向AbstractPlugin,如果它可以转换为该MPL序列中的任何类型。 这里的问题是我的预处理器功能需要我想要创建和加载的所有扩展的完整列表。是否有一些技术可以让我在一个单独的文件中注册每个扩展名?
更新
我相信,我对情况的解释太模糊了,所以我决定让它更具体。
我想定义一组扩展类型。对于每种扩展类型,可以有任意数量的扩展名。在运行期间,程序加载外部库,解析入口点函数,调用它,结果得到一个指针。然后它尝试将该指针强制转换为所有已注册的扩展类型(使用dynamic_cast
,因此扩展类型的类都继承自某些多态基类)。如果对某个扩展类型的强制转换成功,则在对该扩展类型的特殊处理程序的调用中使用已转换的指针。
扩展类型的数量在编译时是已知的(显然,扩展的数量是无限的)。使用我的aproach,loader类使用这些知识来检查是否存在每个扩展类型的处理程序(如果没有,程序不编译)。另外,我的aproach不强制扩展类型的类知道有关加载器的任何信息(因此很容易修改加载器)。但是如果每个扩展类型都注册了它会更方便。
答案 0 :(得分:9)
您可以让所有课程在某种集合中自行注册。这是一个骨架方法:
<强> 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();
};
<强> Base.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>
的构造函数负责以名称Derived
注册类"MyClass"
。您可以通过以下方式动态创建Derived
的实例:
std::unique_ptr<Base> p = Base::instantiate("MyClass");
代码可以/应该通过检测重复注册,打印可用类列表等来改进。注意我们如何避免任何静态初始化排序问题我将实际的注册表映射对象设置为块静态对象,这保证了在首次使用之前进行初始化,因此仅在最后一次使用后才被销毁。
答案 1 :(得分:1)
事实证明我想要的是不可能的。原因是在这个上下文中的“寄存器”意味着“将类型置于类型内部”并且类型序列是不可变的,因为它们本身就是类型。因此,应该手动创建此类型序列,或者有些人建议将“注册”移动到运行时。
答案 2 :(得分:0)
使用抽象工厂模式实现这样的扩展框架并不困难。
http://en.wikipedia.org/wiki/Abstract_factory_pattern
您可以在全局列表中注册这些抽象工厂函数/对象,并根据它做任何您想做的事情。