Reputation: 11499
I'm surprised this doesn't work:
union DlDatum
{
float mFloat;
s32 mInteger;
};
class DlDbE
{
public:
DlDbE( float f ) : mData.mFloat( f ) {};
private:
DlDatum mData;
};
Is there a way to initialize a union in a c++ constructor mem-initializer list?
Update: Answer is to create constructors for union. Didn't know that could be done. Here is what I did:
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;
};
Upvotes: 13
Views: 9507
Reputation:
@AndreyT gives an excellent answer that I will expand on with a little practical advice.
I tend to use unions in order to get easy access to a bitmap value without the tedious and ugly bitwise and's/bitwise or's. I think this is a fairly common practice.
One technique I have used for a while to make the process even easier is if I am working with a bitmap of less than 32bits I declare it as an unnamed struct inside a union along with a companion DWORD data-member. For example:
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;
};
};
With that in place it will work like an 'accessor' function. If you want to set the values you can do so in one go by assigning a number with the appropriate bitmap to this 'accessor'. You want to zero them all - also a piece of cake. It especially works VERY well with the windows registry. In order to store the value of the union bitmap all you need to do is just write the DWORD to the registry! Retrieving it later for re-initialization is equally simple.
A DWORD is one of the native types of the registry and you do not need to mess around static-casting or writing manual conversion functions. If you have a longer bitmap than 32bits you can declare a 64Bit sized-integer and it would work in just the same way generally - and equally well with the registry as a QUADWORD is also a native type.
Where this bears directly on what @AndreyT mentions - if you want convenient initialization of a class data-member in my union-bitmap/DWORD format, all you have to do is - as in the example - make sure the 'accessor' is the first value declared in the union. Then you can mem-list it directly with the new C++11 '{}' scheme. No need for weird union-constructors at all!
A caveat. Where the separate bitmap bits live 'inside' the accessor DWORD will depend on the alignment setting for your structures. This is set at the compiler level or with the __declspec(align(#))
statement in MSVC++ and similar syntax in other compilers.
Finally, an update learned while trying these ideas out in several different scenarios recently. Despite the fact C++11 explicitly says it is legal to initialize a union by its first variable as described above, MSVC++ seems to ignore this standard - or 'not implement' it as the compiler error output states. Therefore if you are using the Microsoft compiler you will have to implement a messy constructor for your union if you want to initialize it. A shame, but presumably compliance to the C++11 standard will improve in further service packs to VS2013 and with the next 2014 iteration of the entire IDE.
Upvotes: 2
Reputation: 320699
In C++03 and before you are limited to writing a constructor for your union.
In C++11 the uniform initialization extents the syntax of aggregate initialization to constructor initializer lists. This means that the good old aggregate initializer syntax like
DlDatum d = { 3.0 };
which we all know and love from C and which initializes the first member of the union, can now be used in constructor initializer lists as well
union DlDatum
{
float mFloat;
s32 mInteger;
};
class DlDbE
{
public:
DlDbE( float f ) : mData{f} {}
private:
DlDatum mData;
};
This feature only allows you to "target" the first non-static member of the union for initialization. If you need something more flexible, then it is back to writing constructors.
Upvotes: 16
Reputation: 146998
Like any other member, if you want to construct a union, you will have to give the union a constructor and call that.
Upvotes: 14