标记联合 C++

Tagged union C++

我正在尝试在 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;
}

我正在使用以下命令使用 clang 进行编译

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

std::string 有一个非常重要的构造函数,因此您需要为 union 编写一个构造函数,在 s 的位置执行放置 new


这是您的代码的一个版本,它向 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;
}