我可以在mem-initializer中初始化一个联合吗?

时间:2012-10-24 19:30:54

标签: c++

我很惊讶这不起作用:

union DlDatum
{
   float  mFloat;
   s32    mInteger;
};

class DlDbE
{
public:
   DlDbE( float f ) : mData.mFloat( f ) {};
private:
   DlDatum mData;
};

有没有办法在c ++构造函数mem-initializer列表中初始化union?

更新:答案是为union创建构造函数。不知道可以做到的。这是我做的:

union DlDatum
{
   float  mFloat;
   s32    mInteger;
   bool   mBoolean;
   u32    mSymbol;
   u32    mObjIdx; 

   DlDatum(         ) : mInteger( 0 ) {}
   DlDatum( float f ) : mFloat( f )   {}
   DlDatum( s32   i ) : mInteger( i ) {}
   DlDatum( bool  b ) : mBoolean( b ) {}
   DlDatum( u32   s ) : mSymbol( s )  {} // this ctor should work for objIdx also
};

class DlDbE
{
public:
   DlDbE() {}
   DlDbE( float f ) : mData( f ) {}
   DlDbE( u32 i   ) : mData( i ) {}
   DlDbE( bool b  ) : mData( b ) {}
   ...etc..
private:
   DlDatum mData;
};

3 个答案:

答案 0 :(得分:14)

在C ++ 03中,在你开始为你的联盟编写构造函数之前。

在C ++ 11中,统一初始化将聚合初始化的语法扩展到构造函数初始化列表。这意味着好的旧聚合初始化器语法如

DlDatum d = { 3.0 };

我们都知道并喜欢来自C并且初始化了union的第一个成员,现在也可以在构造函数初始化列表中使用

union DlDatum
{
   float  mFloat;
   s32    mInteger;
};

class DlDbE
{
public:
   DlDbE( float f ) : mData{f} {}
private:
   DlDatum mData;
};

此功能仅允许您“定位”联合的第一个非静态成员以进行初始化。如果你需要更灵活的东西,那么它又回到编写构造函数。

答案 1 :(得分:13)

与任何其他成员一样,如果你想构建一个union,你必须给union一个构造函数并调用它。

答案 2 :(得分:3)

@AndreyT给出了一个很好的答案,我将通过一些实用的建议进行扩展。

我倾向于使用联合,以便轻松访问位图值,而无需繁琐和丑陋的按位和/或按位或。我认为这是一种相当普遍的做法。

我使用了一段时间使这个过程更容易的技术是,如果我使用的是小于32位的位图,我将其声明为 union <中的未命名的 struct / em>以及随附的 DWORD 数据成员。例如:

union UNICODECONTROL{
    DWORD           dwAccessor;
    struct{
        unsigned unicode_01 : 1;
        unsigned unicode_02 : 1;
        unsigned unicode_03 : 1;
        unsigned unicode_04 : 1;
        unsigned unicode_05 : 1;
        unsigned unicode_06 : 1;
        unsigned unicode_07 : 1;
        unsigned unicode_08 : 1;
        unsigned unicode_09 : 1;
        unsigned unicode_10 : 1;
    };  
};

随着它的到位,它将像'访问者'功能一样工作。如果要设置值,可以通过为此“访问者”分配带有相应位图的数字来一次性完成。你想把它们全部归零 - 也是一块蛋糕。它特别适用于Windows注册表。为了存储union位图的值,您只需将 DWORD 写入注册表即可!稍后检索它以进行重新初始化同样很简单。

DWORD 是注册表的本机类型之一,您无需乱搞静态转换或编写手动转换函数。如果你有一个比32位更长的位图你可以声明一个64位大小的整数,它通常会以相同的方式工作 - 同样适用于注册表,因为 QUADWORD 也是一个本机类型。 / p>

这直接关系到@AndreyT提到的内容 - 如果你想在我的union-bitmap / DWORD 格式中方便地初始化类数据成员,你所要做的就是 - 就像在示例 - 确保'accessor'是union中声明的第一个值。然后,您可以使用新的C ++ 11'{}'方案直接对其进行mem-list。根本不需要奇怪的工会构造者!

警告。如果单独的位图位位于“内部”,则访问器DWORD将取决于结构的对齐设置。这是在编译器级别或MSVC ++中的__declspec(align(#))语句以及其他编译器中的类似语法中设置的。

最后,最近在几个不同的场景中尝试了这些想法时学到了更新。尽管C ++ 11明确表示如上所述通过其第一个变量初始化union是合法的,但MSVC ++似乎忽略了这个标准 - 或者“未实现”它作为编译器错误输出状态。因此,如果您要使用Microsoft编译器,则必须为联合实现一个混乱的构造函数,如果您想要初始化它。遗憾的是,可能符合C ++ 11标准将进一步改进VS2013的服务包以及整个IDE的下一次2014迭代。