2015-05-21 21 views
0

我有這樣的事情:當前向聲明不可能儘可能優雅時,如何解決循環類依賴性?

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))。

問題是,我不能申報v_with_holder,直到我宣佈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&)' 

現在看來,我的唯一的辦法是定義複製構造函數,它們只是創建新的獨特ptrs並複製內容。爲了完整性,還要移動構造函數。這似乎工作(ideone link),但它意味着我已經從我的意圖,這是該得到:

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

// define struct_v, holder 

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

和所有以避免循環依賴!

當然,一定有更好的辦法。告訴我有更好的方法。請。什麼是更好的方法?

+0

爲什麼downvote?讓我知道這是不是題外話,或者我可以如何改進這個問題。 – Claudiu

回答

0

沒關係啊,看來我可以前瞻性聲明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被帶前置聲明工種,或者std::vector可以採取未申報的類型。我認爲,根據this question and answer,它不能,但迄今在ideone,G ++ 4.8.1和MSVC 2012上工作。

如果這在某種程度上是不可能的,問題仍然存在。

+3

有些模板可以處理forward聲明的類型。我相信標準的不是必需的,但其他模板可能會這樣做。像typedefs這樣的其他類型的機器完全不受類型不完整性的影響。 – Puppy

0

爲什麼不能簡單地做:

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

這將沒有適當的複製語義。他們將共享一個指針,而不是深度複製它。 – Claudiu

+0

還有boost :: recursive_variant – Puppy