0

外部 C API を中心にヘッダーのみの C++ ライブラリを作成しようとしています。C API はvoid *ポインタをハンドルとして使用します。アイデアは次のとおりです。

// resource.hpp
class Resource {
public:
    // RAII constructor, destructor, etc.
    // ...
    void do_something(const Handle & h) {
        do_something_impl( (void *) h);
    }
};

// handle.hpp
class Handle
{
public:
    Handle(size_t n, const Resource & res)
        : p_(res.allocate(n)), res_(res) {}

    // cast operation
    operator void *() const { return p_; }

private:
    void * p_;
    Resource & res_;
};

ここでの問題は、(a) ハンドルがリソースへの参照を保持する必要があり、(b) リソースがハンドルを void * にキャストできる必要があることです。残念ながら、これは循環依存につながります。

これを再構築する方法についてのアイデアはありますか?

注: 答えは、単純に「xxx.hpp をインクルード」したり、クラスの 1 つを前方宣言したりすることではありません。これはどうにかして再構築する必要がありますが、どうすればよいかわかりません。

リソース ファイルの先頭に前方宣言として aを追加しclass Handleても機能しません。これは、(void *)キャストがハンドル定義の一部であり、リソースがまだ認識できないためです。同様に、キャストをvoid * ptr()メンバー関数に変更すると、同じ問題が発生します。

関数定義を .cpp ファイルに移動することも答えではありません。ヘッダーのみにする必要があります。

4

2 に答える 2

4

まあ、それは救助のためのテンプレートです(再び!):

// resource.hpp
class Resource;
template<typename TResource> class Handle;

class Resource {
public:
    // RAII constructor, destructor, etc.
    // ...
    void do_something(const Handle<Resource> & h) {
        do_something_impl( (void *) h);
    }
};

// handle.hpp
template<class TResource>
class Handle {
public:
    Handle(size_t n, const TResource & res)
        : p_(res.allocate(n)), res_(res) {}

    // cast operation
    operator void *() const { return p_; }

private:
    void * p_;
    TResource & res_;
};
于 2013-01-15T14:00:35.043 に答える
1

ヘッダー ファイルを相互にインクルードしないでください。代わりに、クラスを前方宣言します。このようにして、参照またはポインタとして使用できます。

したがって、resource.hpp では次のようになります。

class Handle;

class Resource {
public:
    // RAII constructor, destructor, etc.
    // ...
    void do_something(const Handle & h) {
        do_something_impl( (void *) h);
    }
};

そして、handle.hpp で:

class Resource;

class Handle
{
public:
    Handle(size_t n, const Resource & res)
        : p_(res.allocate(n)), res_(res) {}

    // cast operation
    operator void *() const { return p_; }

private:
    void * p_;
    Resource & res_;
};

void*関数内で型キャスト演算子を使用するため、do_somethingその実装を別のソース ファイルに移動する必要があります。そのソース ファイルには両方のヘッダー ファイルを含めることができるため、すべての関数にアクセスできます。

于 2013-01-08T14:26:47.577 に答える