2012-06-24 37 views
5

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

更新:

我相信,我的情况的解释过于含糊,所以我决定把它更加明确。

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

扩展类型的数量在编译时是已知的(显然,扩展的数量是无限的)。使用我的aproach加载器类使用这些知识来检查是否存在每个扩展类型的处理程序(如果没有,程序不会编译)。另外,我的意见并不强制类的扩展类型知道任何关于加载器(所以很容易修改加载器)。但是如果每个扩展类型都注册了,它会更方便。

+0

正在生成一个头可接受的解决方案? – Arpegius

回答

0

事实证明,我想要的是不可能的。其原因是在这个上下文中的“注册”意味着“在类型序列中放置一个类型”,并且类型序列是不可变的,因为它们本身就是类型。所以人们应该手动创建这种类型的序列,或者一些人建议将“注册”移动到运行时。

8

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

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

我们在客户端使用:

派生。 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>的构造函数的名称"MyClass"下注册类Derived的照顾。您可以通过动态创建的Derived实例:

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

的代码可以/应该通过检测重复注册,打印的可用类的列表等。注意我们如何避免我做实际的任何静态初始化顺序的问题得到改善注册表映射对象是一个块静态对象,它保证在第一次使用之前被初始化,并且仅在其最后一次使用之后才被销毁。

+0

我认为是这样的,但我更关心编译时间的问题。我不确定是否存在一个,但是,C++模板的土地却充满了奇迹。 – grisumbras

+0

没有静态的。你不能让类自己注册,因为每个实现文件都有它自己的编译单元,并且每个文件都可以放在不同的库中。这个解决方案的强大之处在于,当你加载一个动态库时,扩展类变成了自动可用的。这是众所周知的非常有用的模式。 – Arpegius

+0

这是一个非常好的实现。我唯一不理解的是静态create()函数上的= 0。据我所知,这是无效的C++,因为静态函数永远不会是虚拟的。那部分应该如何工作? – Shenjoku

相关问题