...在联合问题中不允许使用构造函数

时间:2011-05-16 08:20:28

标签: c++ visual-c++ gcc struct unions

我迫切需要找到解决以下问题的方法:

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&amp; 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'
}


有什么方法可以以某种方式完成这项工作吗?

3 个答案:

答案 0 :(得分:9)

正如@Als所说,联盟不能将非POD定义为成员数据,还有一种选择。您仍然可以将指向非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 :(得分:7)

当前的C ++标准不允许联盟内的非POD类型。因此,您从gcc中获得此编译器错误 您应该使用boost::variant而不是使用C联合。检查doccmentation here

添加到上述内容:
新的C ++标准(C ++ 0x)添加了一个名为 Unrestricted Unions 的新功能,它支持将非POD类型存储到联盟。

答案 2 :(得分:0)

C ++标准2003不允许这样做(来自标准9.5):

  

带有a的类的对象   非平凡的构造函数(12.1),a   非平凡的拷贝构造函数(12.8),a   非平凡的析构函数(12.4),或者   非平凡的复制赋值运算符   (13.5.3,12.8)不能成为a的成员   联盟,也不可能有这样的一系列   对象。

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

来自N3291 9.5:

  

如果有任何非静态数据成员   工会有一个非平凡的违约   构造函数(12.1),复制构造函数   (12.8),移动构造函数(12.8),复制   赋值运算符(12.8),移动   赋值运算符(12.8),或   析构函数(12.4),对应的   联盟的成员函数必须是   用户提供的或隐含的   已删除(8.4.3)联盟。

其他人建议使用Boost.Variant。对于简单的修复,只需从Flag类中删除构造函数。虽然您需要在初始化union对象时手动初始化它,但它不会令人困惑,因为union本质上是一个C功能。