This is legal and very useful in situations where you have different contexts, where different names would be more appropriate. Take a four member vector vec4
type for example (similar to what you'd find in GLSL):
vec4 v(1., 1., 1., 1.);
// 1. Access as spatial coordinates
v.x;
v.y;
v.z;
v.w;
// 2. Access as color coordinates (red, green, blue, alpha)
v.r;
v.g;
v.b;
v.a;
// 3 Access as texture coordinates
v.s;
v.t;
v.p;
v.q;
A vec4 may only have four members of the same type, but you'd use different names to refer to the same objects, depending on the context.
Case in point, data contained in the GLM (OpenGL mathematics) vector use this feature, albeit the code is a bit more intriticate:
# if GLM_CONFIG_XYZW_ONLY
T x, y;
# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION
GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(T, Q, x, y)
# endif//GLM_CONFIG_SWIZZLE
# elif GLM_CONFIG_ANONYMOUS_STRUCT == GLM_ENABLE
union
{
struct{ T x, y; };
struct{ T r, g; };
struct{ T s, t; };
typename detail::storage<2, T, detail::is_aligned<Q>::value>::type data;
# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR
GLM_SWIZZLE2_2_MEMBERS(T, Q, x, y)
GLM_SWIZZLE2_2_MEMBERS(T, Q, r, g)
GLM_SWIZZLE2_2_MEMBERS(T, Q, s, t)
GLM_SWIZZLE2_3_MEMBERS(T, Q, x, y)
GLM_SWIZZLE2_3_MEMBERS(T, Q, r, g)
GLM_SWIZZLE2_3_MEMBERS(T, Q, s, t)
GLM_SWIZZLE2_4_MEMBERS(T, Q, x, y)
GLM_SWIZZLE2_4_MEMBERS(T, Q, r, g)
GLM_SWIZZLE2_4_MEMBERS(T, Q, s, t)
# endif
};
# else
union {T x, r, s;};
union {T y, g, t;};
# if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION
GLM_SWIZZLE_GEN_VEC_FROM_VEC2(T, Q)
# endif//GLM_CONFIG_SWIZZLE
# endif