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は、私が少し実用的なアドバイスで拡張する優れた答えを提供します。

面倒で醜いビット単位および's/ bitwise or'を使用せずに、ビット単位値に簡単にアクセスできるようにするために、共用体を使用する傾向があります。これはかなり一般的な方法だと思います。

プロセスをさらに簡単にするためにしばらく使用してきた手法の1つは、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はレジストリのネイティブタイプの1つであり、静的キャストや手動変換関数の記述をいじくり回す必要はありません。32ビットより長いビットマップを使用している場合は、64ビットサイズの整数を宣言できます。これは、一般的に同じように機能します。また、 QUADWORDもネイティブ型であるため、レジストリでも同様に機能します。

これが@AndreyTの言及に直接関係する場合、私のunion-bitmap / DWORD形式でクラスデータメンバーの便利な初期化が必要な場合は、例のように、「アクセサー」がユニオンで宣言された最初の値。次に、新しいC ++11'{}'スキームを使用して直接mem-listすることができます。奇妙なユニオンコンストラクターはまったく必要ありません!

警告。個別のビットマップビットが「内部」に存在する場合、アクセサDWORDは、構造の配置設定によって異なります。これは、コンパイラレベルで設定されるか__declspec(align(#))、MSVC++のステートメントおよび他のコンパイラの同様の構文で設定されます。

最後に、最近いくつかの異なるシナリオでこれらのアイデアを試している間に学んだアップデート。C ++ 11は、上記のように最初の変数でユニオンを初期化することが合法であると明示的に述べていますが、MSVC ++はこの標準を無視しているようです。または、コンパイラエラー出力の状態として「実装していません」。したがって、Microsoftコンパイラを使用している場合、それを初期化する場合は、ユニオンの厄介なコンストラクタを実装する必要があります。残念ですが、おそらくC ++ 11標準への準拠は、VS2013へのさらなるサービスパックおよびIDE全体の次の2014年の反復で改善されます。

于 2014-11-07T19:35:42.600 に答える