I've got this code that I just compiled successfully :
template <typename T, unsigned int N>
struct Vector
{
struct Vec1
{
T x;
};
struct Vec2 : public Vec1
{
T y;
};
struct Vec3 : public Vec2
{
T z;
};
struct Vec4 : public Vec3
{
T w;
};
template <unsigned int N>
union Data
{
std::array<T, N> components;
};
template <>
union Data<1>
{
Vec1 vec;
std::array<T, 1> components;
};
template <>
union Data<2>
{
Vec2 vec;
std::array<T, 2> components;
};
template <>
union Data<3>
{
Vec3 vec;
std::array<T, 3> components;
};
template <>
union Data<4>
{
Vec4 vec;
std::array<T, 4> components;
};
Data<N> data;
};
It works as intended, however I would like the struct Vector
to expose the data's variables as its own member variables.
Is it possible?
The solution would allow me to do Vector<int, 3> vec; vec.x ...; vec.components[0] ...;
The purpose of the union is to access easily both the vector's components as an array and individually.
Also, if you happen to know a better way to implement the templated union Data
specializations, please say so as I find it kinda hard coded. It would be perfect to recursively add variables without having to add the variables of the previous specialization.
For example, I would only need to declare T x
once.
I think you need to bring some clarity to your design and the code.
Use of
template <>
union Data<3>
{
T x;
T y;
T z;
std::array<T, 3> components;
};
does not sound right. You need to have {x, y, z}
or components
, not x
, or y
, or z
, or components
. What you need is something along the lines of
template <>
union Data<3>
{
struct
{
T x;
T y;
T z;
} members;
std::array<T, 3> components;
};
Having said that, the cleanest member variable is just
std::array<T, N> components;
As far as the member variables are concerned, Vector
can be defined as:
template <typename T, unsigned int N>
struct Vector
{
std::array<T, N> components;
};
If you need to expose the elements of components
through x
, y
, and z
-like abstractions, it will be better to add member functions.
template <typename T, unsigned int N>
struct Vector
{
std::array<T, N> components;
T& x()
{
static_assert(N > 0);
return components[0];
}
T& y()
{
static_assert(N > 1);
return components[1];
}
T& z()
{
static_assert(N > 2);
return components[2];
}
};
with the above definition of Vector
, the following main
function should work.
int main()
{
Vector<int, 1> v1;
v1.x() = 20;
Vector<int, 2> v2;
v2.x() = 20;
v2.y() = 30;
Vector<int, 3> v3;
v3.x() = 20;
v3.y() = 30;
v3.z() = 40;
}
If you use
Vector<int, 2> v2;
v2.z() = 20;
you should get a compile-time error.
You can add the const
versions of the above functions to make the member functions work with const
objects too.
template <typename T, unsigned int N>
struct Vector
{
std::array<T, N> components;
T& x()
{
static_assert(N > 0);
return components[0];
}
T const& x() const
{
static_assert(N > 0);
return components[0];
}
T& y()
{
static_assert(N > 1);
return components[1];
}
T const& y() const
{
static_assert(N > 1);
return components[1];
}
T& z()
{
static_assert(N > 2);
return components[2];
}
T const& z() const
{
static_assert(N > 2);
return components[2];
}
};