简体   繁体   English

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

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

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 (eg with calls to ss.push_back(v) ). 其他所有代码都具有标准的,已经定义的数据类型和类,因此可以复制构造它们,并且代码库可以这样编写(例如,调用ss.push_back(v) )。

The issue is that I can't declare v_with_holder until I declare holder , and vice versa. 问题是,直到我声明holder ,我才能声明v_with_holder ,反之亦然。 A forward declaration class holder; 前瞻性声明class holder; gives field 'h' has incomplete type 'holder' . 给出field 'h' has incomplete type 'holder'

I thought I could use a unique_ptr : 我以为我可以使用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: 但是,现在的问题是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&)'

Now it seems that my only recourse is to define copy constructors which just make new unique ptrs and copy the contents. 现在看来,我唯一的求助方法就是定义复制构造函数,这些复制构造函数将创建新的唯一ptrs并复制内容。 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: 这似乎可行( ideone link ),但这意味着我从我的意图中得到了帮助,这是这样的:

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? 这是什么更好的方法?

Why not simply do: 为什么不简单地做:

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

Ah okay, it appears I can forward-declare v_with_holder instead: 好的,看来我可以转发声明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;
};

I did not realize that typedef s will work with forward-declared types, or that std::vector can take an undeclared type. 我没有意识到typedef可以与前向声明的类型一起使用,或者std::vector可以采用未声明的类型。 I thought, based on this question and answer , that it couldn't, but this has worked so far on ideone, G++ 4.8.1, and MSVC 2012. 根据这个问题和答案 ,我认为它不可能,但是到目前为止,它已经在ideone,G ++ 4.8.1和MSVC 2012上奏效。

The question still stands if this were somehow not possible. 问题仍然存在,如果这不可能。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么前向声明和指针(或引用?)可以解决循环依赖关系? - Why forward declaration and pointer (or reference?) can resolve circular dependency? 前向声明和循环依赖 - Forward declaration & circular dependency 循环依赖结构,使用前向声明时对结构进行错误重新定义 - Circular dependency struct, error redefinition of struct when using forward declaration 如何使用带有boost :: msm的前向声明来避免循环依赖? - How to use forward declaration with boost::msm to avoid circular dependency? 为什么前向声明不能解决循环依赖关系? - Why does a forward declaration not fix the circular dependency? 循环依赖项(typedef上的类,classdef上的typedef),正向声明给出了模糊的调用? - circular dependency (class on typedef, typedef on class), forward declaration gives ambigous call? 是否有可能我有一个类的前向声明,而不在头文件中使它们成为引用或指针 - Is it possible I have forward declaration of a class, without making them reference or pointer in header file c ++“不允许不完整的类型”访问类引用信息时出错(带有前向声明的循环依赖) - c++ “Incomplete type not allowed” error accessing class reference information (Circular dependency with forward declaration) 我什么时候可以使用前向声明? - When can I use a forward declaration? 是否可以在循环依赖中导航? - Is it possible to navigate around the circular dependency?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM