Reputation: 9852
Given class.mem/28:
https://eel.is/c++draft/class.mem#general-28
Which states:
In a standard-layout union with an active member of struct type T1, it is permitted to read a non-static data member m of another union member of struct type T2 provided m is part of the common initial sequence of T1 and T2; the behavior is as if the corresponding member of T1 were nominated.
I think its valid to create a union with multiple (different) structs each with a uint64_t
member:
template<some params>
struct CustomField
{
void operator=(uint64_t newVal)
{
val = someCustomInsertFn(newVal);
}
operator uint64_t() const
{
return someCustomExtractFn(val);
}
uint64_t val; // Note that this is used in a union and so aliases with all other fields and the `all` below
};
Then:
union CheckedBitField
{
struct { uint64_t all; }
CustomField<some param> fieldOne;
CustomField<some other param> fieldTwo;
};
The idea being this is a simple union with structure members each of which just has a uint64_t val
.
But those custom fields have custom void operator=(uint64_t newVal)
and operator uint64_t() const
operators which can add additional checks over what you can get with a basic bitfield.
An example of the insert function is to add additional checks that the value you are writing is logically valid and/or wont be truncated.
So this code is valid - just like in a normal bitfield:
CheckedBitField b{};
b.fieldOne = 5; // This runs custom code.
Does adding those additional functions break the class.mem/28 rules and/or am I missing something?
Full runnable code - which adds the functionality to set the min/max value of a field: https://godbolt.org/z/ozz16GEP8
Upvotes: 0
Views: 95
Reputation: 76859
b.fieldOne = 5;
has undefined behavior already before anything in your quote could become relevant.
The fieldOne
member is not active, therefore the corresponding member subobject is not in its lifetime and calling a non-static member function on it is therefore UB.
The assignment also won't start the lifetime and make the member active because =
is neither the built-in operator nor a trivial assignment operator in this case. (That's the only exception where new
or a function that implicitly creates objects isn't needed to change the active member of a union.)
And also, the quote specifically is about reading the inactive members, not writing to them, which is still UB regardless of whether the rule applies.
Upvotes: 0