§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.
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?.
[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.
By definition here, POD is a simple class with no user-defined constructors, non static members, and containing simple data types only.
The question is, will these 2 classes below be equivalent as POD types (in terms of memory footprint):
class pod
{
public:
int x;
double y;
};
class pod1
{
public:
int x;
double y;
enum POD_TYPE
{
POD1 = 0,
POD = 1
};
};
In other words does adding enum to the class only affects scope resolution of enum and does not affect properties of the class itself? By observation, it seems that class is still pod, but I would like to confirm based on the standard.
Yes, that type is still POD. The definition is given by C++11 9/10:
A POD struct is a non-union class that is both a trivial class and a standard-layout class, and has no non-static data members of type non-POD struct, non-POD union (or array of such types).
Trivial means that it doesn't do any funny business when creating, destroying or copying objects. Standard-layout means that it doesn't do any funny business with the layout of data members: no polymorphism, and restrictions on what you can do with access specifiers and inheritance. These terms are fully defined in C++11 9/6 and 9/7, if you want more detail.
Nested types (such as your enumeration), static data members and non-virtual member functions (apart from constructors etc. which would make it non-trivial) will not effect any of those things, so it is still POD.
UPDATE: Since you say you're interested in historic definitions, C++03 defined:
9/4 A POD-struct is an aggregate class that has no non-static members of type non-POD-struct, non-POD-union (or array of such types), and has no user-defined copy assignment operator and no user-defined destructor"
8.5.1/1 An aggregate is an array or class with no user-declared constructors, no private or protected non-static data members, no base classes and no virtual functions.
So there were more restrictions; but nested types were still allowed. I don't have a copy of C++98, but I'm sure that would be identical to C++03.
It doesn't make any difference regarding POD status because defining a nested enum does not add data members to the class. In fact, you could also define a nested class that is not POD inside pod1 and it would still not make a difference regarding the PODness of pod1.
The enum POD_TYPE is a type and won't effect the layout, we can see this from the draft C++ standard section 9.2 Class members paragraph 1 which says:
[...]Members of a class are data members, member functions (9.3), nested types, and
enumerators. Data members and member functions are static or non-static; see 9.4. Nested types are classes (9.1, 9.7) and enumerations (7.2) [...]
as opposed to data members and we can further see that the definition of a standard layout class depends only on data member from paragraph 16 which says:
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).
and we further see going back to section 9 Classes paragraph 10 which says(emphasis mine):
A POD struct108 is a non-union class that is both a trivial class and a standard-layout class, and has no non-static data members of type non-POD struct, non-POD union (or array of such types). Similarly, a POD union is a union that is both a trivial class and a standard layout class, and has no non-static data members of type non-POD struct, non-POD union (or array of such types). A POD class is a class that is either a POD struct or a POD union.
As far as I can tell the pre C++11 standard does not diff much in the above items.
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.