如何转发声明应该属于类的模板化类型

How to forward declare templated type that should belong to a class?

本文关键字:属于 类型 何转发 转发 声明      更新时间:2023-10-16

假设我有两个类:

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也这样做?

解决此问题的方法之一是

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

不能正向声明嵌套的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;
};

在类X中有一个"这就是引用对象X的方式"的typedef是一个糟糕的设计决定,正是因为您需要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;
};

不幸的是,您不能正向声明嵌套的typedef。然而,您可以使用全局typedef,如

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;

当我想转发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;
};