如何前置声明应属于类的模板类型?

10
假设我有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
解决这个问题的设计层面方法可能是引入第三个类,该类将了解其他两个类。 - Ashalynd
即使您可以前向声明 B::Ref,这对您也不够,因为您需要该类型的成员的定义。 - eerorika
不是重复的问题,因为这个问题不仅仅是一个简单的typedef前向声明。模板化的变量有很大的不同。 - Mike Lischke
5个回答

8
解决这个问题的一种方式是:
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 std::shared_ptr<T> Ptr; - Ashalynd

4

由于在前向声明时 B 是不完整的类型,因此无法前向声明嵌套的 typedef。不过,您可以按以下方式解决问题:

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

这是我最喜欢的部分,因为它只需要进行一次修改(我们使用“std::shared_ptr<B> _b”代替“B:Ref _b”)。其他所有内容都保持不变。简单而美丽。 - Mike Lischke

2
在类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;
};

1

很遗憾,您无法前向声明嵌套的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;

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

除非您也继承了std::shared_ptr的构造函数,否则这将几乎不可能使用。 - Angew is no longer proud of SO
@Angew 感谢你的提示。现在这个答案更像是“如果你真的想要躲避typedef……”。否则我会觉得P0W的答案更有吸引力。 - TobiMcNamobi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接