当无法尽可能优雅地进行前向声明时,如何解决循环 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;
};
我没有意识到 typedef
s 可以使用前向声明的类型,或者 std::vector
可以采用未声明的类型。我认为,基于 this question and answer,它不能,但到目前为止,这在 ideone、G++ 4.8.1 和 MSVC 2012 上有效。
如果这在某种程度上是不可能的,那么问题仍然存在。
我有这样的东西:
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;
};
我没有意识到 typedef
s 可以使用前向声明的类型,或者 std::vector
可以采用未声明的类型。我认为,基于 this question and answer,它不能,但到目前为止,这在 ideone、G++ 4.8.1 和 MSVC 2012 上有效。
如果这在某种程度上是不可能的,那么问题仍然存在。