当无法尽可能优雅地进行前向声明时,如何解决循环 class 依赖?

How can I resolve a circular class dependency when forward declaration is not possible as elegantly as possible?

我有这样的东西:

struct v_with_holder {
    // bunch of fields
    holder h; // does not name a type
};

typedef boost::variant</* such types, */v_with_holder/*, many others */> struct_v;

class holder { public: std::vector<struct_v> ss; };

我最近才添加了这个特定的变体。所有其他的只有标准的、已经定义的数据类型和 类,因此它们可以被复制构造,并且代码库是这样编写的(例如调用 ss.push_back(v))。

问题是在声明 holder 之前我无法声明 v_with_holder,反之亦然。前向声明 class holder; 给出 field 'h' has incomplete type 'holder'

我想我可以使用 unique_ptr:

class holder;
struct v_with_holder {
    // bunch of fields
    std::unique_ptr<holder> ph;
    holder& h;
    v_with_holder(); 
    ~v_with_holder();
};

typedef boost::variant</* such types, */v_with_holder/*, many others */> struct_v;

class holder { public: std::vector<struct_v> ss; };

v_with_holder::v_with_holder() : ph(new holder), h(*ph) { }
v_with_holder::~v_with_holder() { }

但是,现在的问题是 v_with_holder 不再是可复制构造的:

holder h1, h2;
v_with_holder x;
x.h = h2;
h1.ss.push_back(x); // error: use of deleted function 'v_with_holder::v_with_holder(const v_with_holder&)'

现在看来我唯一的办法就是定义复制构造函数,它只创建新的唯一指针并复制内容。为了完整起见,也移动构造函数。这似乎有效(ideone link),但这意味着我已经从我的意图中得到了:

struct v_with_holder {
    // bunch of fields
    holder h;
}

// define struct_v, holder

对于这种可怕的事情:

class holder;
struct v_with_holder {
    // a bunch of fields
    std::unique_ptr<holder> ph;
    holder& h;

    friend void swap(v_with_holder& first, v_with_holder& second) 
    {
        using std::swap;
        // swap a bunch of fields
        swap(first.ph, second.ph);
    }

    v_with_holder(); 
    ~v_with_holder();
    v_with_holder(const v_with_holder& other);
    v_with_holder(v_with_holder&& other);
    v_with_holder& operator=(v_with_holder other);
};

// define struct_v, holder

v_with_holder::v_with_holder() : ph(new holder), h(*ph) { }
v_with_holder::~v_with_holder() { }
v_with_holder::v_with_holder(const v_with_holder& other) : ph(new holder), h(*ph)
{
    // copy a bunch of fields
    h = other.h;
}
v_with_holder::v_with_holder(v_with_holder&& other) : v_with_holder()
{
    swap(*this, other);
}
v_with_holder& v_with_holder::operator=(v_with_holder other)
{
    swap(*this, other);
    return *this;
}

所有这些都是为了避免循环依赖!

当然,一定有更好的方法。告诉我有更好的方法。请。这是什么更好的方法?

为什么不简单地做:

struct v_with_holder {
    // bunch of fields
    holder *h; //Pointer to holder is of known size
};

typedef boost::variant</* such types, */v_with_holder/*, many others */> struct_v;

class holder { public: std::vector<struct_v> ss; };

啊好吧,看来我可以转发声明 v_with_holder 而不是:

struct v_with_holder;

typedef boost::variant</* such types, */v_with_holder/*, many others */> struct_v;

class holder { public: std::vector<struct_v> ss; };

struct v_with_holder
{
    holder h;
};

我没有意识到 typedefs 可以使用前向声明的类型,或者 std::vector 可以采用未声明的类型。我认为,基于 this question and answer,它不能,但到目前为止,这在 ideone、G++ 4.8.1 和 MSVC 2012 上有效。

如果这在某种程度上是不可能的,那么问题仍然存在。