In C++, I'm trying to create a specialized point class as a union, like so:
union point
{
struct { float x, y, z; };
float val[3];
float operator[](unsigned i) { return val[i]; }
};
So that I can access the point as an array or as multiple points, for readability.
However, let's say that I want to generalise this a bit:
template<unsigned n>
union point
{
struct { float ???; };
float val[n];
float operator[](unsigned i) { return val[i]; }
};
What can I put for ???
? I could have x
, x, y
, x, y, z
, or x, y, z, w
depending on what n
is. Solution? Forward declarations!
template<unsigned n>
union point
{
struct coords;
float val[n];
float operator[](unsigned i) { return val[i]; }
};
template<>
struct point::coords<3>
{
float x, y, z;
};
// ...
But this doesn't appear to work. Under the GCC 4.6, it compiles, however, whenever that I try to use the members, like so:
point<3> val;
val.x;
I get the error:
error: ‘union point<3>’ has no member named ‘x’
Even if I change val.x
to val.coords::x
, I still get the error:
error: ‘union point<3>::coords’ is not a base of ‘union point<3>’
Adding using coords;
in the union definition didn't help, either.
Is there any way to accomplish this under the GCC 4.6? Is there a different method of doing this? Is it even possible?
I would suggest using variadic macro to define your union<N>
templates.
template<unsigned int N>
union point; // declared and undefined
#define DECLARE_POINT(NUM, ...) \
template<> \
union point<NUM> \
{ \
struct { float __VA_ARGS__; }; \
float val[NUM]; \
}
#undef DECLARE_POINT
Having done this, you can simply declare/define your various combinations for coordinates (before #undef
in this case):
DECLARE_POINT(1, x);
DECLARE_POINT(2, x, y);
DECLARE_POINT(3, x, y, z);
that is equivalent to,
template<> union point<1> { struct { float x; }; float val[1]; };
template<> union point<2> { struct { float x, y; }; float val[2]; };
template<> union point<3> { struct { float x, y, z; }; float val[3]; };
It can be used in the same way you asked:
point<3> p;
p.z = 0;
Also, you can put a cross check using some template trickery (static_assert
) to check the number arguments(e.g. 1,2,3,...
) match the total argument passed (e.g. x,y,z,...
).