2016-02-26 246 views
1

我想在C++文件中編譯下面的標記聯合,並且遇到問題。有人可以解釋我缺少什麼,或者我必須改變以使下面的工作?我曾嘗試網上找這件事,不幸已經變得無處...Tagged union C++

#include <string> 
using std::string; 
#include <iostream> 
using std::cout; 
using std::endl; 
#include <new> 

const int TU_STRING = 0; 
const int TU_INT = 1; 
const int TU_FLOAT = 2; 

struct TU { 
    int type; 
    union { 
    int i; 
    float f; 
    std::string s; 
    } u; 

    TU(const TU& tu) : type(tu.type) { 
    switch (tu.type) { 
     case TU_STRING: new(&u.s)(tu.u.s); break; 
     case TU_INT: u.i = tu.u.i;  break; 
     case TU_FLOAT: u.f = tu.u.f;  break; 
    } 
    } 
    ~TU() { 
    if (tu.type == TU_STRING) 
     u.s.~string(); 
    } 
}; 

int main() { 
    TU tu; 

    return 0; 
} 

我鏗鏘使用以下命令

g++ -std=c++14 some.cpp 

,我獲得了大量的編譯錯誤

some.cpp:18:4: error: call to implicitly-deleted default constructor of 'union (anonymous union at some.cpp:12:4)' 
    TU(const TU& tu) : type(tu.type) { 
^
some.cpp:15:18: note: default constructor of '' is implicitly deleted because variant field 's' has a non-trivial default constructor 
    std::string s; 
       ^
some.cpp:18:4: error: attempt to use a deleted function 
    TU(const TU& tu) : type(tu.type) { 
^
some.cpp:15:18: note: destructor of '' is implicitly deleted because variant field 's' has a non-trivial destructor 
    std::string s; 
       ^
some.cpp:20:13: error: use of undeclared identifier 'TU_STRING' 
     case TU_STRING: new(&u.s)(tu.u.s); break; 
      ^
some.cpp:20:34: error: unknown type name 'tu' 
     case TU_STRING: new(&u.s)(tu.u.s); break; 
           ^
some.cpp:20:36: error: expected ')' 
     case TU_STRING: new(&u.s)(tu.u.s); break; 
           ^
some.cpp:20:33: note: to match this '(' 
     case TU_STRING: new(&u.s)(tu.u.s); break; 
           ^
some.cpp:21:13: error: use of undeclared identifier 'TU_INT' 
     case TU_INT: u.i = tu.u.i;  break; 
      ^
some.cpp:22:13: error: use of undeclared identifier 'TU_FLOAT' 
     case TU_FLOAT: u.f = tu.u.f;  break; 
      ^
some.cpp:26:10: error: use of undeclared identifier 'tu' 
    if (tu.type == TU_STRING) 
     ^
some.cpp:26:21: error: use of undeclared identifier 'TU_STRING' 
    if (tu.type == TU_STRING) 
        ^
some.cpp:25:4: error: attempt to use a deleted function 
    ~TU() { 
^
some.cpp:15:18: note: destructor of '' is implicitly deleted because variant field 's' has a non-trivial destructor 
    std::string s; 
       ^
some.cpp:32:8: error: no matching constructor for initialization of 'TU' 
    TU tu; 
    ^
some.cpp:18:4: note: candidate constructor not viable: requires single argument 'tu', but no arguments were provided 
    TU(const TU& tu) : type(tu.type) { 
^
11 errors generated. 
的編譯

謝謝!

編輯:更新後的代碼仍然不工作

struct VariantType { 

    enum class Tag {INTEGER, STRING}; 
    Tag tag; 
    union TypeUnion { 
     string inner_string; 
     int inner_int; 

     TypeUnion(const std::string& str) { 
      new(&inner_string) string(str); 
     } 
     TypeUnion(int inner_int_in) { 
      inner_int = inner_int_in; 
     } 
     TypeUnion(std::string other) : inner_string{std::move(other)} {} 
    } type_union; 

    VariantType(const std::string& str) : tag{Tag::STRING} { 
     new(&this->type_union.inner_string) string(str); 
    } 
    VariantType(int inner_int_in) : tag{Tag::INTEGER} { 
     this->type_union.inner_int = inner_int_in; 
    } 
}; 
+0

這在我看來有點像你會嘗試使用C. C++有其他更好的方法來模擬C++實現你想要做的事情(爲一個字符串,一個int或者一個float實現一個通用包裝),比如繼承和模板。 – tofro

回答

8

std::string有一個不平凡的構造函數,所以你需要編寫一個構造函數用於執行在s的位置放置newunion


以下是您的代碼版本,它將構造函數添加到union。我不認爲這是最好的解決方案,但它表明你需要做什麼:

#include <iostream> 
#include <new> 
#include <string> 
#include <utility> 

const int TU_STRING = 0; 
const int TU_INT = 1; 
const int TU_FLOAT = 2; 

struct TU { 
    union my_union { 
     struct i_type { int type; int i; } i; 
     struct f_type { int type; float f; } f; 
     struct s_type { int type; std::string s; } s; 

     my_union(int i) : i{TU_INT, i} {} 
     my_union(float f) : f{TU_FLOAT, f} {} 
     my_union(std::string s) : s{TU_STRING, std::move(s)} {} 
     my_union(my_union const& other) { 
      // This is safe. 
      switch (other.i.type) { 
      case TU_INT: ::new(&i) auto(other.i); break; 
      case TU_FLOAT: ::new(&f) auto(other.f); break; 
      case TU_STRING: ::new(&s) auto(other.s); break; 
      } 
     } 
     ~my_union() { 
      // This is safe. 
      if (TU_STRING == s.type) { 
       s.~s_type(); 
      } 
     } 
    } u; 

    TU(int i) : u(i) {} 
    TU(float f) : u(f) {} 
    TU(std::string s) : u(std::move(s)) {} 
    TU(TU const&) = default; 
    ~TU() = default; 
}; 

int main() { 
    TU tu("hello"); 
    std::cout << tu.u.s.s << '\n'; 
    return 0; 
} 
+0

你可以編輯我有上面這樣做的文件嗎?我想我已經這樣做了... – Curious

+0

我認爲我確實在構造函數中爲結構提供了一個放置新構造... – Curious

+0

@Curious - 嘗試在Simple的答案中詢問你不懂**的內容 – Elemental