10

我很惊讶这不起作用:

union DlDatum
{
   float  mFloat;
   s32    mInteger;
};

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

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

更新:答案是为联合创建构造函数。不知道可以这样做。这是我所做的:

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

3 回答 3

15

在 C++03 和之前,您仅限于为您的联合编写构造函数。

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

DlDatum d = { 3.0 };

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

union DlDatum
{
   float  mFloat;
   s32    mInteger;
};

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

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

于 2012-10-24T19:52:10.943 回答
13

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

于 2012-10-24T19:32:57.137 回答
3

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

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

我已经使用了一段时间以使该过程变得更加容易的一种技术是,如果我使用小于 32 位的位图,我将其声明为联合内的未命名结构以及伴随的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 注册表。为了存储联合位图的值,您只需将DWORD写入注册表!稍后检索它以进行重新初始化同样简单。

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

这与@AndreyT 提到的内容直接相关——如果你想以我的联合位图/ DWORD格式方便地初始化类数据成员,你所要做的就是——如示例所示——确保“访问器”是在联合中声明的第一个值。然后,您可以直接使用新的 C++11 '{}' 方案对其进行内存列表。根本不需要奇怪的联合构造函数!

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

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

于 2014-11-07T19:35:42.600 回答