Как переслать объявить шаблонный тип, который должен принадлежать классу?

Предположим, что у меня есть 2 класса:

class A
{
public:
  typedef std::shared_ptr<A> Ref;
  ...

private:
  B::Ref _b;
}

class B
{
public:
  typedef std::shared_ptr<B> Ref;
  ...

private:
  A::Ref _a;
}

Это, очевидно, требует прямого объявления классов B и B:: Ref. Переслать декларацию B просто, но как это сделать для B:: Ref тоже?

Ответ 1

Вы не можете переслать объявление вложенным typedef, поскольку в точке прямого объявления B будет неполным. Однако вы можете решить свою проблему, как показано ниже:

class B;

class A {
  std::shared_ptr<B> _b;
public:
  typedef std::shared_ptr<A> Ref;
};

class B {
  A::Ref _a;
public:
  typedef std::shared_ptr<B> Ref;
};

Ответ 2

Одним из способов решения этой проблемы является

class A;
class B ;

template <typename T>
struct Traits {
    typedef std::shared_ptr<T>  Ptr; 
};


class A
{
    private:
      Traits<B>::Ptr _b;
};

class B
{
    private:
      Traits<A>::Ptr _a;
};

Ответ 3

Наличие typedef для "это то, как вы относитесь к объектам X" внутри класса X является плохим дизайнерским решением, именно потому, что вам нужно полное определение X, чтобы увидеть его членов, но вы хотите иметь возможность ссылаться на X без его полного определения.

Я вижу два способа решения этого. Один из них заключается в том, чтобы отказаться от обзора и просто вызвать typedef RefA, определяемый там, где класс объявлен вперед:

class A;
typedef std::shared_ptr<A> RefA;

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

template <class T>
struct RefT
{
  typedef T *type;  // Default reference type
};

template <class T>
using Ref = typename RefT<T>::type;


class A;
template <>
struct RefT<A>
{
  typedef std::shared_ptr<A> type;
};


class B
{
private:
  Ref<A> _a;
};

Ответ 4

К сожалению, вы не можете перенаправить объявление вложенного typedef. Однако вы можете просто использовать глобальные typedefs, например

typedef std::shared_ptr<B> RefB ;

и т.д. Другим решением является использование поздней специализированной специализации шаблона, например:

template <typename T> class BImpl;

template <typename T>
class AImpl
{
public:
    typedef std::shared_ptr<AImpl> Ref;
private:
    typename BImpl<T>::Ref _b;
};

template <typename T>
class BImpl
{
public:
    typedef std::shared_ptr<BImpl> Ref;
    typename AImpl<T>::Ref _a;
};

typedef AImpl<void> A;
typedef BImpl<void> B;

Ответ 5

Когда мне хочется пересылать typedef, я всегда считаю наследование. Это может выглядеть так:

template<typename T>
class Ref : public std::shared_ptr<T>
{
    Ref()
    {}
    Ref(T *t)
        : std::shared_ptr<T>(t)
    {}
};

class B;

class A
{
public:
    //...

private:
    Ref<B> _b;
};

class B
{
public:
    //...

private:
    Ref<A> _a;
};