Циркулярная зависимость с использованием директивы, где предварительные объявления не работают - PullRequest
3 голосов
/ 16 марта 2020

Я работаю с базой кодов, где не могу решить эту циклическую зависимость:

foo.h

class Foo
{
public:
  using Ptr = std::shared_ptr<Foo>;
  using ConstPtr = std::shared_ptr<const Foo>;

  void setter(const Bar::Ptr& bar_ptr) {};

private:
  Bar::WeakPtr bar_ptr_;
};

и

bar.h

class Bar
{
public:
  using Ptr = std::shared_ptr<Bar>;
  using ConstPtr = std::shared_ptr<const Bar>;
  using WeakPtr = std::weak_ptr<Bar>;

  Bar(Foo::ConstPtr foo_ptr) : foo_ptr_(std::move(foo_ptr)) {};

private:
  Foo::ConstPtr foo_ptr_;
};

Ранее он компилировался, поскольку существовал внешний заголовок, в котором:

using FooPtr = std::shared_ptr<Foo>;
using FooConstPtr = std::shared_ptr<const Foo>;
using BarPtr = std::shared_ptr<Bar>;

Но поскольку требуется согласованность, я бы хотел получить Foo::Ptr, Foo::ConstPtr, Bar::Ptr. Есть ли шанс, что я смогу его получить?

Coliru

РЕДАКТИРОВАТЬ: добавил Bar::WeakPtr, который ранее отсутствовал, так как я думал, что у меня уже были проблемы.

Ответы [ 2 ]

2 голосов
/ 16 марта 2020

Возможно, это недостаток C ++. Вы не можете объявить только некоторые публичные c имена классов, не включая полное определение класса. В этом случае я боюсь, что ваша круговая зависимость не может быть решена - по крайней мере, таким образом, чтобы это не укусило вас в будущем.

Однако, в качестве альтернативы, рассмотрите возможность использования определений шаблонов. вне предметного класса. Это меняет порядок терминов, но не общее значение:

template<class T>
struct PtrStruct {
    using type = std::shared_ptr<T>;
};

template<class T>
using Ptr = typename PtrStruct<T>::type;

template<class T>
struct ConstPtrStruct {
    using type = std::shared_ptr<const T>;
};

template<class T>
using ConstPtr = typename PtrStruct<const T>::type;

В этой настройке ваш Foo::Ptr становится Ptr<Foo>, а Foo::ConstPtr становится ConstPtr<Foo>. Вы все еще можете:

  • на более поздней стадии заменить std::shared_ptr чем-то другим в одном месте, где определено PtrStruct. Остальная часть кода будет скомпилирована без изменений, если используемый интерфейс не изменился.
  • специализируют PtrStruct для указания c T, если это должно быть что-то отличное от остальных.
0 голосов
/ 16 марта 2020

Если требуется последовательность, не создавайте плохо сформированные структуры. Вы можете попробовать что-то вроде:


// Foo.h

class Bar;

class Foo
{
public:
  using BarPtr = std::shared_ptr<Bar>;

  void setter( BarPtr bar_ptr)
  {}
};


// Bar.h

class Foo;

class Bar
{
public:
  using ConstFooPtr=std::shared_ptr<const Foo>;

  Bar( ConstFooPtr foo_ptr)
      : foo_ptr_( std::move( foo_ptr))
  {}

private:
  ConstFooPtr foo_ptr_;
};

...