Круговая зависимость библиотеки только для заголовков

Я пытаюсь создать библиотеку 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_;
};

Проблема здесь в том, что (а) дескриптор должен сохранять ссылку на ресурс, и (б) ресурс должен иметь возможность привести дескриптор к пустоте *. К сожалению, это приводит к круговой зависимости.

Любые идеи о том, как реструктурировать этот?

ПРИМЕЧАНИЕ. Ответ заключается не в том, чтобы просто «включить xxx.hpp» или в предварительном объявлении одного из классов.
Это нужно как-то реструктурировать, я просто не могу понять, как это сделать.

Добавление class Handle так как прямое объявление к началу файла ресурсов не работает, потому что (void *) приведение является частью определения дескриптора, которое Resource все еще не видит. Аналогично, изменение актерского состава на void * ptr() Функция-член приводит к той же проблеме.

Перемещение определений функций в файл .cpp также не является ответом — оно должно быть только заголовком.

0

Решение

Ну, это шаблоны на помощь (СНОВА!):

// 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_;
};
2

Другие решения

Не включайте файлы заголовков друг в друга, вместо этого у вас есть предварительная декларация классы. Таким образом, они могут быть использованы в качестве ссылок или указателей.

Итак, в 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* Оператор Typecasting внутри do_something функция, вы должны переместить эту реализацию в отдельный исходный файл. В этот исходный файл вы можете включить оба заголовочных файла, чтобы получить доступ ко всем функциям.

1

По вопросам рекламы [email protected]