I have this piece of code:
class test {
private:
union {
double x;
std::vector<double> y;
} amIValid;
};
I wonder if the union instance amIValid is valid?
An unnamed union can be instantiated in C++:
union { int i; double d; } my_thing;
my_thing.i = 3;
// etc.
An anonymous union is an unnamed union that is not instantiated (scroll down). You can access its members directly:
union { int i; double d; };
i = 3;
// etc.
So the answer to the question in the title is that an anonymous union cannot be instantiated because instantiating it means that it is not an anonymous union.
Consider the following code:
static const struct X
{
int a;
} x={1};
X y;
It compiles, and X appears to work in the declaration of y. But is it actually true that static const and similar cv-qualifiers and storage duration specifiers don't affect the definition of X? I.e. is the following exactly equivalent to the above?
struct X
{
int a;
};
static const X x={1};
X y;
Name X in declaration
static const struct X
{
int a;
} x={1};
introduces type specifier struct X. Thus this declaration
X y;
is equivalent to
struct X y;
As for storage class specifiers then according to the C++ Standard (7.1.1 Storage class specifiers)
... The storage-class-specifier applies to the name declared by each init-declarator in the list and not to any names declared by other specifiers.
So in this declaration
static const struct X
{
int a;
} x={1};
static is a storage class specifier of declarator x that is present in init-declarator x={1}
If you would use for example a typedef
typedef const struct
{
int a;
} X;
then in this case type name X would indeed have qualifier const.
So if you will define for example
X x = { 1 };
then x will be a constant object. You will be unable to write
x.a = 2;
Nevertheless you may not specify a storage class specifier in a typedef because as it is said in the quote storage class specifiers may be specified only for init-declarators.
However you may write
static X x = { 1 };
because the storage class specifier is applied to x that has type const X
This question already has answers here:
Why does C++ disallow anonymous structs?
(7 answers)
Closed 8 years ago.
How would you go about doing this in standard C++11/14 ? Because if I'm not mistaken this isn't standard compliant code with the anonymous structs.
I wish to access the members the same way as you would with this.
template <typename some_type>
struct vec
{
union {
struct { some_type x, y, z; };
struct { some_type r, g, b; };
some_type elements[3];
};
};
Yes, neither C++11 nor C++14 allow anonymous structs. This answer contains some reasoning why this is the case. You need to name the structs, and they also cannot be defined within the anonymous union.
§9.5/5 [class.union]
... The member-specification of an anonymous union shall only define non-static data members. [ Note: Nested types, anonymous unions, and functions cannot be declared within an anonymous union. —end note ]
So move the struct definitions outside of the union.
template <typename some_type>
struct vec
{
struct xyz { some_type x, y, z; };
struct rgb { some_type r, g, b; };
union {
xyz a;
rgb b;
some_type elements[3];
};
};
Now, we require some_type to be standard-layout because that makes all the members of the anonymous union layout compatible. Here are the requirements for a standard layout type. These are described in section §9/7 of the standard.
Then, from §9.2 [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).
18 If a standard-layout union contains two or more standard-layout structs that share a common initial sequence, and if the standard-layout union object currently contains one of these standard-layout structs, it is permitted to inspect the common initial part of any of them. Two standard-layout structs share a common initial sequence if corresponding members have layout-compatible types and either neither member is a bit-field or both are bit-fields with the same width for a sequence of one or more initial members.
And for the array member, from §3.9/9 [basic.types]
... Scalar types, standard-layout class types (Clause 9), arrays of such types
and cv-qualified versions of these types (3.9.3) are collectively called standard-layout types.
To ensure that some_type is standard layout, add the following within the definition of vec
static_assert(std::is_standard_layout<some_type>::value, "not standard layout");
std::is_standard_layout is defined in the type_traits header. Now all 3 members of your union are standard layout, the two structs and the array are layout compatible, and so the 3 union members share a common initial sequence, which allows you to write and then inspect (read) any members belonging to the common initial sequence (the entire thing in your case).
Anonymous unions are allowed in C++11/14. See the example of their usage at Bjarne Stroustrup's C++11 FAQ
Regarding anonymous structs see Why does C++11 not support anonymous structs, while C11 does? and Why does C++ disallow anonymous structs and unions?
Though most compilers support anonymous structs, if you want your code to be standard compliant you have to write something like this:
template <typename some_type>
struct vec
{
union {
struct { some_type x, y, z; } s1;
struct { some_type r, g, b; } s2;
some_type elements[3];
};
};
I think the other answers sort of missed the point of the question:
I wish to access the members the same way as you would with this.
In other words, the question is really "how do I define a type vec in a standard-compliant manner such that given an object u of that type, u.x, u.r, and u.elements[0] all refer to the same thing?"
Well, if you insist on that syntax...then the obvious answer is: references.
So:
template <typename some_type>
struct vec
{
vec() = default;
vec(const vec& other) : elements{ other.elements[0], other.elements[1], other.elements[2] } {}
vec & operator=(const vec &other) {
elements[0] = other.elements[0];
elements[1] = other.elements[1];
elements[2] = other.elements[2];
return *this;
}
some_type elements[3];
some_type &x = elements[0], &y = elements[1], &z = elements[2];
some_type &r = elements[0], &g = elements[1], &b = elements[2];
};
The first problem with this approach is that you need extra space for 6 reference members - which is rather expensive for such a small struct.
The second problem with this approach is that given const vec<double> v;, v.x is still of type double &, so you could write v.x = 20; and have it compile without warning or error - only to get undefined behavior. Pretty bad.
So, in the alternative, you might consider using accessor functions:
template <typename some_type>
struct vec
{
some_type elements[3];
some_type &x() { return elements[0]; }
const some_type &x() const { return elements[0]; }
some_type &y() { return elements[1]; }
const some_type &y() const { return elements[1]; }
some_type &z() { return elements[2]; }
const some_type &z() const { return elements[2]; }
some_type &r() { return elements[0]; }
const some_type &r() const { return elements[0]; }
some_type &g() { return elements[1]; }
const some_type &g() const { return elements[1]; }
some_type &b() { return elements[2]; }
const some_type &b() const { return elements[2]; }
};
You would have to write u.x() etc. instead of u.x, but the space savings is considerable, you can also rely on the compiler-generated special member functions, it's trivially copyable if some_type is (which enables some optimizations), it's an aggregate and so can use the aggregate initialization syntax, and it's also const-correct.
Demo. Note that sizeof(vec<double>) is 72 for the first version and only 24 for the second.
If I declare an anonymous union in a function…
void f(int in) {
union { int i; float f; };
// …
}
…does syntax exist to initialize it (other than assigning to i or f in another statement? A quick look at the spec suggests no. The obvious ones don’t compile:
// Nope:
union { int i = in; float f; };
union { int i; float f; } = in;
union { int i; float f; } = {in};
union { int i; float f; }{in};
union { int i; float f; }(in);
This works (at least in gcc 4.7.2):
union { int i; float f; } x = {1};
Notice that the type (i.e. the union) is anonymous but its instanciation is called x.
What you were trying to achieve (e.g. union { int i; float f; }{in};) doesn't compile but suppose it did. Then you would be creating an unnamed object (a temporary) of an unnamed type. The temporary would be destroyed at the end of the expression and, therefore, this statement would have no effect. So what's the point?
See update below -- I'm not sure whether this is a language restriction or a compiler limitation.
In the absence of designated initializers (added to C in 1999, so far nonexistent in C++ as far as I know), an initializer for a union can only specify a value for the first named member:
union { int i; float f; } obj = { 42 }; // sets obj.i to 42
C, as of the 1999 standard, provides designated initializers that let you initialize any named member you like:
union { int i; float f; } obj = { .f = 1.25 };
Since C++ doesn't have this feature, you're pretty much out of luck unless you happen to want to initialize the first named member.
Of course you can use an assignment:
union { int i; float f; } obj;
obj.f = 1.25;
which I suggest is a perfectly good workaround. You can do what you want; you just can't do it with the syntax you want.
Giving the union type a name wouldn't be particularly helpful in this case, unless you make it visible in a wider scope and write a function that returns a value of the type:
union u { int i; float f; };
u init_f(float f) { u result; result.f = f; return result; }
// later
u obj = init_f(1.25);
UPDATE :
I wasn't aware of the existence of anonymous union in C++ when I wrote the above. C11 permits anonymous unions and structs, but only as members of an enclosing union or struct. C++11 permits an anonymous union object to be defined, as in this example from the standard:
void f() {
union { int a; const char* p; };
a = 1;
p = "Jennifer";
}
g++ 4.7.2 seems not to permit anonymous union objects to be initialized. For example, this:
int main() {
union {
int i;
float f;
} = { 42 };
}
results in the following errors with g++ -std=c++11:
c.cpp: In function ‘int main()’:
c.cpp:5:5: error: expected ‘;’ after union definition
c.cpp:5:7: error: expected primary-expression before ‘=’ token
I don't see anything in section 9.5 of the C++11 standard that forbids initializers for anonymous unions, which makes me think that this is a limitation of g++, presumably to be corrected in a future release.
Whether this limitation is imposed by the language or by g++, you can work around it either by giving the union a name:
union { int i; float f; } obj = { 42 };
(but then you have to refer to obj.i and obj.f rather than just i and f), or by using an assignment rather than an initializer:
union { int i; float f; };
i = 42;
(I'll clean up this answer once we resolve whether this restriction is imposed by the language or by the compiler.)
Point from ISO C++ Standard: section 9.5, para 4, line 1:
"A union for which objects or pointers are declared is not
an anonymous union."
Example :
struct X {
union {
int i;
double d;
} ;
int f () { return i;}
};
int main() { return 0; }
IAm expecting an error from this example according to the above point
but GCC,SUN compiler CC,EDG,etc are not showing error
iam expecting this error// error : cannot directly access "i"
please ..conform above example program is correct are wrong
This would make the union not anonymous:
struct X {
union {
int i;
double d;
} *p;
int f () { return i;} // !Nyet.
};
Cheers & hth.,
To add to what Alf is saying, the purpose of the anonymous union language in the C++ spec is to allow scoping of the unions members. If you have a named union inside a struct:
struct X {
union {
int i;
double d;
} varname;
};
i is not a member of the struct X. i is a member of varname, which itself is a member of struct X.
However, if the union doesn't have a member variable declared, then i would have to be accessed directly as a member of X. This can only work if the union has no name (no variables are declared with the union definition). Such unions are called "anonymous unions".