Click here to Skip to main content
15,887,434 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi!

I have the following code (with some unnecessary details removed):

Header:
C++
enum class TargetType : uint8
{
	NoTarget
	, Location
	, Actor
};


class Target
{
public:

	Target();
	Target(const FVector &inLocation);
	Target(const AActor *inTargetActor);

	// ... some methods here

private:

	TargetType targetType;

	union
	{
		FVector location;
		TWeakObjectPtr<AActor> targetActor;
	};
};


Source:
C++
// ... header includes

Target::Target()
	: targetType { TargetType::NoTarget }
{
}

Target::Target(const FVector &inLocation)
	: targetType { TargetType::Location }
	, location(inLocation)
{
}

Target::Target(const AActor *inTargetActor)
	: targetType { TargetType::Actor }
	, targetActor(inTargetActor)
{
}

// ... some code


When I try to compile this I get the following errors:
error C4582: 'Target::location': constructor is not implicitly called
error C4582: 'Target::targetActor': constructor is not implicitly called
error C4582: 'Target::targetActor': constructor is not implicitly called
error C4582: 'Target::location': constructor is not implicitly called


The compiler complains about the union members not being initiated. The first constructor complains about both members not being initiated. The other two complains about the member not being initiated, so e.g. if I want to use the location, the compiler wants me to initiate the targetActor as well.

My question is do I really have to initiate both members if I'm not going to use them, e.g. in the first constructor? For me it makes no sense since I don't want to use the data in that case? Also why do I have to initiate
Target::location
when I want to use
Target::targetActor
as the active member? I'm I missing something here?

Thanks in advance!

What I have tried:

I'm sure someone understands better than me what's going on!
Thankful for all help!

Note: I use C++11 but only the C++14 tag existed?
Posted
Updated 17-May-17 1:40am
v2

Which compiler version (I guess Microsoft)?
I have tested similar code (using other union member types) with the GNU compiler and got no errors.

Depending on the C++11 support of the compiler it might be sourced be the union members being not POD data types:
Unions cannot contain a non-static data member with a non-trivial special member function (copy constructor, copy-assignment operator, or destructor). (until C++11)


If a union contains a non-static data member with a non-trivial copy/move constructor, copy/move assignment, or destructor), that function is deleted by default in the union and needs to be defined explicitly by the programmer.

If a union contains a non-static data member with a non-trivial default constructor, the default constructor of the union is deleted by default unless a variant member of the union has a default member initializer.

At most one variant member can have a default member initializer. (since C++11)

So it might be solved by providing appropiate constructors (which requires using a non anonymous union):
union loc
{
    FVector location;
    TWeakObjectPtr<AActor> targetActor;
    loc() { /* initialise one member here */ }
    loc (const FVector &inLocation) { location = inLocation; }
    loc (const AActor *inTargetActor) { targetActor = inTargetActor; }
};
 
Share this answer
 
Comments
WaZoX 17-May-17 7:57am    
Thanks for your suggestion.

I changed the union to this:

union TargetData
{
TargetData() { location = FVector(); }
TargetData(const FVector &inLocation) { location = inLocation; }
TargetData(AActor *inActor) { targetActor = inActor; }

FVector location;
TWeakObjectPtr<aactor> targetActor;
} targetData;

Now I get the complains at the union instead. E.g. for the empty constructor I get the following errors:
error C4582: 'Target::TargetData::location': constructor is not implicitly called
error C4582: 'Target::TargetData::targetActor': constructor is not implicitly called
...
Jochen Arndt 17-May-17 8:29am    
Then I have no more ideas besides checking if the error can be ignored (I guess it is initially a warning but you have enabled treating warnings as errors):
#pragma warning (disable: 4582)
// problematic code here (the complete union)
#pragma warning (enable: 4582)

But when doing so you must ensure that the members has been initialised before using them.

I don't know the types but guess that that at least TWeakObjectPtr is a template. If at least one member is kind of complex I would not use it within a union to avoid side effects. Then it might be better to use a struct when the additional memory consumption can be accepted.

I searched for the error number and did not find it on a MSDN or page. So it might be better to ask in a MSDN VC++ forum where a compiler developer might answer. As last resort you can also contact the MS support.
WaZoX 22-May-17 7:33am    
That did the trick.

Yes it's a template type so you are probably right. It makes sense to allow some additional memory consumption to avoid side effects!

Thanks a lot for your help!
Jochen Arndt 22-May-17 7:42am    
Thank you for the feedback and accepting my solution.
You need to give the union a name to access its members within the class. See Unions[^].
 
Share this answer
 
Comments
WaZoX 17-May-17 7:26am    
Thanks for your reply! A name for the union isn't needed in the link you posted, see the "Unrestricted Unions" example. I looked at it before but can't understand why I can't get my code to work. For me that example looks pretty much the same as mine?
Richard MacCutchan 17-May-17 7:48am    
Maybe it has something to do with the object types in the union. Sorry, I cannot think of anything else.
WaZoX 17-May-17 7:59am    
I will have to investigate that further. Thanks!

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900