11

実行時に拡張機能を動的にロードするアプリケーションを作成しようとしています。Boost Preprocessor ライブラリを使用して、名前のリストを指定すると、名前ごとにクラスを宣言し (そして、それらすべてを AbstractPlugin クラスのサブクラスにします)、そのクラスを含む Boost MPL シーケンスを宣言するプリプロセッサ関数を作成しました。次に、その MPL シーケンス内のいずれかの型にキャストできる場合、AbstractPlugin へのポインターを試行するクラスを作成しました。ここでの問題は、プリプロセッサ関数が、作成してロードするすべての拡張機能の完全なリストを必要とすることです。各拡張機能を個別のファイルに登録できる手法はありますか?

アップデート:

私の状況説明は漠然としすぎていたと思いますので、より具体的に説明することにしました。

拡張タイプのコレクションを定義したいと思います。拡張子の種類ごとに、任意の数の拡張子が存在する可能性があります。実行時に、プログラムは外部ライブラリをロードし、エントリ ポイント関数を解決して呼び出し、結果としてポインタを取得します。次に、そのポインターをすべての登録済み拡張タイプにキャストしようとします ( を使用dynamic_castするため、拡張タイプのクラスはすべてポリモーフィックな基本クラスから継承されます)。拡張型へのキャストが成功した場合、キャストされたポインターは、その拡張型の特別なハンドラーへの呼び出しで使用されます。

拡張機能の種類の数はコンパイル時に認識されます (もちろん、拡張機能の数は無限です)。私のアプローチを使用すると、ローダー クラスはこの知識を使用して、拡張機能の種類ごとにハンドラーが存在するかどうかを確認します (存在しない場合、プログラムはコンパイルされません)。また、私のアプローチでは、拡張タイプのクラスにローダーに関する情報を強制することはありません (したがって、ローダーを変更するのは簡単です)。ただし、各拡張タイプがそれ自体を登録すると、より便利になります。

4

3 に答える 3

13

You can make all your classes self-registering in some sort of collection. Here's a skeleton approach:

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

Now to use this in a client:

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

The constructor of the Base::Registrar<Derived> takes care of registering the class Derived under the name "MyClass". You can create instances of Derived dynamically via:

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

The code could/should be improved by detecting repeat registrations, printing a list of available classes, etc. Note how we avoid any static initialization ordering problems my making the actual registry map object a block-static object, which is guaranteed to be initialized before its first use, and thus destroyed only after its last use.

于 2012-06-24T09:13:58.200 に答える
0

抽象ファクトリパターンを使用してこのような拡張フレームワークを実装することは難しくありません。

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

これらの抽象ファクトリ関数/オブジェクトをグローバルリストに登録し、それに基づいてやりたいことを何でも行うことができます。

于 2012-06-24T07:40:54.600 に答える