[class.union.anom]/4
A union-like class is a union or a class that has an anonymous union
as a direct member. A union-like class X has a set of variant
members. If X is a union, a non-static data member of X that is
not an anonymous union is a variant member of X. In addition, a
non-static data member of an anonymous union that is a member of X
is also a variant member of X. At most one variant member of a
union may have a default member initializer.
English is not my native language, but just by reading this paragraph I have the impression that the highlighted sentence above applies only to the case where X is a union, which would turn this definition incomplete, as it would miss the definition of a variant member in a class. So, I must conclude that the highlighted sentence must apply to both cases, unions and classes. Could anyone confirm this? If that is not the case, then I think we a have a defect in this paragraph.
I have the impression that the highlighted sentence above applies only to the case where X is a union
The highlighted sentence applies to any union-like class X that has an anonymous union member. X may be a non-union class.
An example:
struct X { // union-like, non-union class X
union { // anonymous union member of X
int i; // non-static data member of anonymous union
float f;
}
}
i and f are variant members of the union like class X, as per the highlighted rule.
Related
Standard-layout class describes a standard layout class that:
has no non-static data members of type non-standard-layout class (or array of such types) or reference,
has no virtual functions and no virtual base classes,
has the same access control for all non-static data members,
has no non-standard-layout base classes,
has all non-static data members and bit-fields in the class and its base classes first declared in the same class, and
given the class as S, has no element of the set M(S) of types as a base class, where M(X) for a type X is defined as:
If X is a non-union class type with no (possibly inherited) non-static data members, the set M(X) is empty.
If X is a non-union class type whose first non-static data member has type X0 (where said member may be an anonymous union), the set M(X) consists of X0 and the elements of M(X0).
If X is a union type, the set M(X) is the union of all M(Ui) and the set containing all Ui, where each Ui is the type of the ith non-static data member of X.
If X is an array type with element type Xe, the set M(X) consists of Xe and the elements of M(Xe).
If X is a non-class, non-array type, the set M(X) is empty.
(numbered for convivence)
However, the following fails:
#include <type_traits>
struct A {
int a;
};
struct B : A {
int b;
};
static_assert(std::is_standard_layout<A>::value, "not standard layout"); // succeeds
static_assert(std::is_standard_layout<B>::value, "not standard layout"); // fails
Demo
I see that 1-4 are true, so is one of points under 5 false? I find the points under 5 a little confusing.
The cppreference description is a little confusing.
The standard (search "standard-layout class is") says:
A standard-layout class is a class that:
has no non-static data members of type non-standard-layout class (or array of such types) or reference,
has no virtual functions (10.3) and no virtual base classes (10.1),
has the same access control (Clause 11) for all non-static data members,
has no non-standard-layout base classes,
either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and
has no base classes of the same type as the first non-static data member.
You can see from the part I emphasized that a class with a non-static data member and a base class that itself has a non-static data member is not standard-layout.
I suspect this point is described as follows in cppreference:
has all non-static data members and bit-fields in the class and its base classes first declared in the same class
The point is that you must be able to cast the address of a standard-layout class object to a pointer to its first member, and back. It boils down to compatibility between C++ and C.
See also: Why is C++11's POD "standard layout" definition the way it is?.
As the (Working Draft of) C++ Standard says:
9.5.1 [class.union]
In a union, at most one of the non-static data members can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time. [...] The size of a union is sufficient to contain the largest of its non-static data members. Each non-static data member is allocated as if it were the sole member of a struct. All non-static data members of a union object have the same address.
But I don't know how to identify which is the active member of an union and I'm not used enough to dive into the standard to locate what the standard says about it, I've tried to figure how the active member is setted but I've found how it is swapped:
9.5.4 [class.union]
[ Note: In general, one must use explicit destructor calls and placement new operators to change the active member of a union. —end note ] [Example: Consider an object u of a union type U having non-static data members m of type M and n of type N. If M has a non-trivial destructor and N has a non-trivial constructor (for instance, if they declare or inherit virtual functions), the active member of u can be safely switched from m to n using the destructor and placement new operator as follows:
u.m.~M();
new (&u.n) N;
—end example ]
So my guess is that the active member of an union is the one first asigned, used, constructed or placement-new'ed; but this becomes kind of tricky with uniform initialization, consider the following code:
union Foo
{
struct {char a,b,c,d;};
char array[4];
int integer;
};
Foo f; // default ctor
std::cout << f.a << f.b << f.c << f.d << '\n';
Which is the active member of the union on the code above? Is std::cout reading from the active member of the union? What about the code below?
Foo f{0,1,2,3}; // uniform initialization
std::cout << f.a << f.b << f.c << f.d << '\n';
With the lines above we can initialize the nested anonymous struct or either the array, if I provide only an integer I can initialize Foo::a or Foo::array or Foo::integer... which one would be the active member?
Foo f{0}; // uniform initialization
std::cout << f.integer << '\n';
I guess that the active member would be the aninymous struct in all of the above cases but I'm not sure.
If I want to activate one or the other union member, should I provide a constructor activating it?
union Bar
{
// #1 Activate anonymous struct
Bar(char x, char y, char z, char t) : a(x),b(y),c(z),d(t) {}
// #2 Activate array
Bar(char (&a)[4]) { std::copy(std::begin(a), std::end(a), std::begin(array)); }
// #3 Activate integer
Bar(int i) : integer(i) {}
struct {char a,b,c,d;};
char array[4];
int integer;
};
I'm almost sure that #1 and #3 will mark as active union the anonymous struct and the integer but I don't know about the #2 because in the moment we reach the body of the constructor the members are already constructed! so are we calling std::copy over an inactive union member?
Questions:
Which are the active union members of Foo if it is constructed with the following uniform initialization:
Foo{};
Foo{1,2,3,4};
Foo{1};
In the #2 constructor of Bar the Bar::array is the active union member?
Where in the standard can I read about which is exactly the active union member and how to set it without placement new?
Your concern about the lack of a rigorous definition of the active member of a union is shared by (at least some of) the members of the standardization committee - see the latest note (dated May 2015) in the description of active issue 1116:
We never say what the active member of a union is, how it can be changed, and so on. [...]
I think we can expect some sort of clarification in future versions of the working draft. That note also indicates that the best we have so far is the note in the paragraph you quoted in your question, [9.5p4].
That being said, let's look at your other questions.
First of all, there are no anonymous structs in standard C++ (only anonymous unions); struct {char a,b,c,d;}; will give you warnings if compiled with reasonably strict options (-std=c++1z -Wall -Wextra -pedantic for Clang and GCC, for example). Going forward, I'll assume we have a declaration like struct { char a, b, c, d; } s; and everything else is adjusted accordingly.
The implicitly defaulted default constructor in your first example doesn't perform any initialization according to [12.6.2p9.2]:
In a non-delegating constructor, if a given potentially constructed
subobject is not designated by a mem-initializer-id (including the
case where there is no mem-initializer-list because the constructor
has no ctor-initializer), then
(9.1) - if the entity is a non-static data member that has a brace-or-equal-initializer and either
(9.1.1) - the constructor’s class is a union (9.5), and no other variant member of that union is designated by a mem-initializer-id or
(9.1.2) - the constructor’s class is not a union, and, if the entity is a member of an anonymous union, no other member of that union is designated by a mem-initializer-id,
the entity is initialized as specified in 8.5;
(9.2) - otherwise, if the entity is an anonymous union or a variant member (9.5), no initialization is performed;
(9.3) - otherwise, the entity is default-initialized (8.5).
I suppose we could say that f has no active member after its default constructor has finished executing, but I don't know of any standard wording that clearly indicates that. What can be said in practice is that it makes no sense to attempt to read the value of any of f's members, since they're indeterminate.
In your next example, you're using aggregate initialization, which is reasonably well-defined for unions according to [8.5.1p16]:
When a union is initialized with a brace-enclosed initializer, the
braces shall only contain an initializer-clause for the first
non-static data member of the union. [ Example:
union u { int a; const char* b; };
u a = { 1 };
u b = a;
u c = 1; // error
u d = { 0, "asdf" }; // error
u e = { "asdf" }; // error
— end example ]
That, together with brace elision for the initialization of the nested struct, as specified in [8.5.1p12], makes the struct the active member. It answers your next question as well: you can only initialize the first union member using that syntax.
Your next question:
If I want to activate one or the other union member, should I provide a constructor activating it?
Yes, or a brace-or-equal-initializer for exactly one member according to [12.6.2p9.1.1] quoted above; something like this:
union Foo
{
struct { char a, b, c, d; } s;
char array[4];
int integer = 7;
};
Foo f;
After the above, the active member will be integer. All of the above should also answer your question about #2 (the members are not already constructed when we reach the body of the constructor - #2 is fine as well).
Wrapping up, both Foo{} and Foo{1} perform aggregate initialization; they're interpreted as Foo{{}} and Foo{{1}}, respectively, (because of brace elision), and initialize the struct; the first one sets all the struct members to 0 and the second one sets the first member to 1 and the rest to 0, according to [8.5.1p7].
All standard quotes are from the current working draft, N4527.
Paper N4430, which deals with somewhat related issues, but hasn't been integrated into the working draft yet, provides a definition for active member:
In a union, a non-static data member is active if its name refers to an object whose lifetime has begun and has not ended ([basic.life]).
This effectively passes the buck to the definition of lifetime in [3.8], which also has a few issues open against it, including the aforementioned issue 1116, so I think we'll have to wait for several such issues to be resolved in order to have a complete and consistent definition. The definition of lifetime as it currently stands doesn't seem to be quite ready.
The active member is the last member you wrote to. Simple as that.
The term is not defined by C++ because it is defined by English.
§9.5/9 from the C++11 Standard (emphasis mine):
A union-like class is a union or a class that has an anonymous union as a direct member. A union-like class X has a set of variant members. If X is a union, a non-static data member of X that is not an anonymous union is a variant member of X.
Is the part in bold saying that between a union-like class that is either a class or a union, only if it is a union can it have a non-static variant member that is not an anonymous union? If this is so, why? And what practical difference does it make in code?
I'm actually questioning whether this statement meant to say "If X is a union-like class...". It would make full sense to me then.
Either way, this clause has been bugging me for the past few days and I wish to fully comprehend what it is stating.
No, your attempted clarification is wrong. Here is a union-like class X:
struct X
{
int a;
union {
double b;
long c;
};
};
X::a is a non-static data member of a union-like class X that is not an anonymous union. But it most definitely is NOT a variant member.
All non-static data members of a union are variant members. For union-like classes which are not unions, only those nested within union subobjects are variant members.
I feel your pain, it takes many years of cognitive damage caused by looking over standards documents, to be able to correctly parse that sort of stuff.
only if it is a union can it have a non-static variant member that is not an anonymous union?
Not quite.
It's not saying that only the union version of a union-like class can have the non-static blah blah blah.
What it's saying is both can have it (technically, it's not saying that but it's declining to refute the possibility), but only the union version will have it treated as "a variant member of X".
Seems like latest publicly avalable draft (2013-10-13) have a more refined definition, quote:
A union-like class is a union or a class that has an anonymous union
as a direct member. A union-like class X has a set of variant
members. If X is a union, a non-static data member of X that is
not an anonymous union is a variant member of X. In addition, a
non-static data member of an anonymous union that is a member of X
is also a variant member of X. At most one variant member of a union
may have a brace-or-equal-initializer. Example:
union U {
int x = 0;
union { };
union {
int z;
int y = 1; // error: initialization for second variant member of U
};
};
As for the question, the bolded part is actually defines what is a variant member, which a union-like class has to have (by having a union as a direct member) to be a union-like class.
Does ISO C++ (11) permit a private non-static class member variable to be optimised away?
This could be detected:
class X { int x; };
assert (sizeof(X) >= sizeof(int));
but I am not aware of a clause that demands the assertion above.
To clarify: (a) Is there a clause in the C++ Standard that ensure the assertion above.
(b) Can anyone think of any other way to detect the elision of x?
[offsetof?]
(c) Is the optimisation permitted anyhow, despite (a) and (b)?
I have a feeling the optimisation could be possible if the class is local to a function but not otherwise (but I'd like to have a definitive citation).
I do not think it is forbidden, but I think it is impractical.
§9 Classes [class]
7/ A standard-layout class is a class that:
has no non-static data members of type non-standard-layout class (or array of such types) or reference,
has no virtual functions (10.3) and no virtual base classes (10.1),
has the same access control (Clause 11) for all non-static data members,
has no non-standard-layout base classes,
either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and
has no base classes of the same type as the first non-static data member.107
8/ A standard-layout struct is a standard-layout class defined with the class-key struct or the class-key class.
... thus class X { int x; }; is a standard-layout struct.
§9.2 Class members [class.mem]
16/ Two standard-layout struct (Clause 9) types are layout-compatible if they have the same number of non-static data members and corresponding non-static data members (in declaration order) have layout-compatible types (3.9).
... thus class X { int x; }; is layout-compatible with struct Y { int y; };.
The unfortunate thing is that layout-compatible is not formally defined in the Standard. However given the use of the word layout it seems the intent is to declare that two layout-compatible types should have the same underlying representation.
Therefore, to be able to remove the x in X one would have to prove that all structures that are layout-compatible (such as Y) are amenable to the same optimization (to keep the layout compatibility). It seems quite... improbable... in any non-trivial program.
I am new to C++. I read very frequently from some sites that variant member?.
class School
{
int x; -> data member.
}
I know data member. but what is variant member ?
NOTE:
From the c++ specification: Under Constructor page.
X is a union-like class that has a variant member with a non-trivial default constructor.
"Variant member" is defined in 9.5/8 of C++11:
A union-like class is a union or a class that has an anonymous union
as a direct member. A union-like class X has a set of variant members.
If X is a union its variant members are the non-static data members;
otherwise, its variant members are the non-static data members of all
anonymous unions that are members of X.
In other words, all the non-static data members of a union are "variant members", and for a class containing any anonymous unions, their non-static data members are "variant members" of the class.
The context that you quoted is 12.1/5, saying that if a union-like class has a variant member with a non-trivial default constructor, then the default constructor of the class itself is deleted. The problem is which variant member should be constructed by the default constructor of the class, and the solution is not to have a default constructor. If all variant members have trivial default constructors there's no problem, since by doing nothing the default constructor of the class is constructing all/none of them equally.
boost::variant is a separate thing. I wouldn't be too surprised if "some sites" say "variant members" when they mean "the possible types that a given boost::variant can hold", that is to say the "members" of that variant. But that's not the meaning newly-defined in the C++11 standard.
The term variant is usually employed to identify a member that can hold a value of a set of different types. Similar to a union in the language, the term variant is usually reserved for types that allow the storage of the different options in a type safe way.
You might want to read over the documentation of the boost variant library for one such example, and if that does not clear up the concept, drop a comment/create a question with your doubts.
Boost Variant
A variant is a structure containing a union member and an unsigned integer member that describes which member of the union is currently being used. If you don't know what a union is, read about it first, and then come back.