I have something like this:
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; };
I only added this particular variant recently. All the other ones just have standard, already-defined data types and classes, so they can be copy-constructed, and the code base is written as such (e.g. with calls to ss.push_back(v)
).
The issue is that I can't declare v_with_holder
until I declare holder
, and vice versa. A forward declaration class holder;
gives field 'h' has incomplete type 'holder'
.
I thought I could use a 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() { }
However, the issue now is that v_with_holder
is no longer copy-constructible:
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&)'
Now it seems that my only recourse is to define copy constructors which just make new unique ptrs and copy the contents. And for completeness, move constructors as well. This seems to work (ideone link), but it means that I have gotten from my intent, which was this:
struct v_with_holder {
// bunch of fields
holder h;
}
// define struct_v, holder
To this horribleness:
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;
}
And all to avoid a circular dependency!
Surely, there must be a better way. Tell me there is a better way. Please. What is this better way?