Reputation: 619
I am learning OpenGL as an exercise, and want to roll my own math library for it to get comfortable programming with C++11 templates. The solution to this problem should not invoke runtime-polymorphism.
The basic idea is that I want something like this (note that this obviously is not valid C++ code):
template<class T, int n> //element type is T, size is n
class Vector {
T v1, v2, ... , vn;
public:
Vector(T v1, ... , T vn);
~Vector() noexcept;
...
// more constructors and stuff here.
}
template<T, n>
Vector<T, n> operator +(Vector<T, n> lhs, Vector<T, n> rhs);
...
// more math functions and operators here...
The problem is that I want to convert these vectors into regular C structs transparently when they are passed as arrays to OpenGL functions. For example, for n == 3
, I want to convert my Vector<T, 3>
into something like:
template<class T>
struct Vec3 {
T v1, v2, v3;
}
So that I can do the call:
Vector<float, 3> vertices[1];
vertices[0] = Vector<float, 3>(1.0f, 1.0f, 1.0f);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
and have it just work, as if I had used an array of Vec3<float>
's. I want this behavior for n == 2
, n == 3
, and n == 4
. I don't want to have to write 3 classes and implement math operators for each one.
My first attempt tried to use SFINAE with the casting operator: operator T()
.
// Inside Vector's declaration...
public:
operator typename std::enable_if<n == 3, Vec3<T>>::type();
This might have worked fine for only n == 3
, but I also needed:
operator typename std::enable_if<n == 2, Vec2<T>>::type();
operator typename std::enable_if<n == 4, Vec4<T>>::type();
And g++ complained that the enable_if
didn't have a ::type
typedef for 2 and 4 when I instantiated a Vector<float, 3>
.
At this point I was using a std::array<T, n>
to hold my values, but I realized this didn't really work. Would this not mean that my values weren't actually IN the class, and held somewhere else, so that passing an array of the class would be like passting an array of std::array<T, n>
, not an array of Vec3<T>
?
My current area of interest is in using a std::tuple<class... Types>
, since they store the values directly in the class. There are a few problems with this idea:
operator Vec3<T>()
and friends somehow.sizeof(tuple<float, float, float>) == sizeof(Vec3<float>)
, or any guarentees about memory layout that allows me to safely (say) cast a tuple<float, float, float>
into a Vec3<float>
. I've heard g++'s stdlib stores the tuple values in reverse order inside the class, for example.Upvotes: 4
Views: 947
Reputation: 171127
std::array<T, n>
is guaranteed to be a zero-overhead wrapper over T[n]
, so you can simply store that in your class and be sure there's no padding which could mess up OpenGL calls.
Upvotes: 4