2011-05-16 33 views
7

我迫切需要找到以下问题的解决方案:...与构造不允许在工会问题

namespace test 
{ 
    template <int param = 0> struct Flags 
    { 
     int _flags; 

     Flags() 
     { 
      _flags = 0; 
     } 

     Flags(int flags) 
     { 
      _flags = flags; 
     } 

     void init() 
     { 

     } 
    }; 

    union example 
    { 
     struct 
     { 
      union 
      { 
       struct 
       { 
        Flags<4096> f; 
       }p1; //error: member 'test::example::<anonymous struct>::<anonymous union>::<anonymous struct> test::example::<anonymous struct>::<anonymous union>::p1' with constructor not allowed in union 

       struct 
       { 
        Flags<16384> ff; 
       }p2; //error: member 'test::example::<anonymous struct>::<anonymous union>::<anonymous struct> test::example::<anonymous struct>::<anonymous union>::p2' with constructor not allowed in union 
      }parts; 

      byte bytes[8]; 
     }data; 

     int data1; 
     int data2; 
    } 
} 


这是令人沮丧,如果我添加标签,以P1和P2结构,代码将编译,但F & FF成员将无法访问:

... 
struct p1 
{ 
    Flags<4096> f; 
}; 

struct p2 
{ 
    Flags<4096> ff; 
}; 
... 

void test() 
{ 
    example ex; 
    ex.data.bytes[0] = 0; //Ok 
    ex.data.parts.p1.f.init(); //error: invalid use of 'struct test::example::<anonymous struct>::<anonymous union>::p1' 
} 


有什么办法,使这项工作不知何故?

回答

8

正如@Als所说,union不能将non-POD定义为成员数据,还有一种选择。你仍然可以定义一个指向non-POD的指针作为union的成员数据。

所以这是允许的:

union 
{ 
    struct 
    { 
     Flags<4096> *pf; //pointer to non-POD 
    }p1; 
    struct 
    { 
     Flags<16384> *pff; //pointer to non-POD 
    }p2; 
}parts; 

但随后Boost.Variant是一个更好的选择。

+1

非常感谢,伙计们! – Ryan 2011-05-16 08:43:05

7

当前的C++标准不允许工会内的非POD类型。因此你从gcc得到这个编译器错误。
而不是使用C联合,您应该使用boost::variant。检查文档here

要添加到上面:
新的C++标准(C++ 0X)增加了一个称为Unrestricted Unions新功能,该功能支持存储非POD类型加入到Union。

+0

C++委员会喜欢惊叹号...什么是不允许non-pod类型的一点? – Calmarius 2013-09-14 08:53:48

0

C++标准2003不允许此(从标准9.5):

与 非平凡构造(12.1),一个 非平凡复制构造的类的对象(12.8) (12.4)或 非平凡复制赋值运算符 (13.5.3,12.8)不能是 联合体的成员,也不能是此类对象的数组。

但是,C++ 0x允许它,但是,您需要定义自己的构造函数,因为如果您没有定义自己的构造函数,默认构造函数将被声明为删除。

从N3291 9.5:

如果 工会的任何非静态数据成员有一个不平凡的默认 构造函数(12.1),拷贝构造函数 (12.8),移动构造函数(12.8),复制 赋值运算符(12.8),移动 赋值运算符(12.8),或 析构函数(12.4),并集的对应 成员函数必须是 用户提供的或将被隐含地 删除(8.4.3),用于工会。

其他人建议Boost.Variant。为了简单修复,只需从Flag类中移除构造函数即可。尽管初始化联合对象时需要手动初始化它,但它不会令人困惑,因为联合本质上是一个C特性。