I'm trying to write a math vector class. A first version goes like :
template <typename T, unsigned int n>
struct Vector {
Vector<T, n>(T t = T()) // default
{
for (int i = 0; i < n; i++)
{
data[i] = t;
}
}
Vector<T, n>(const Vector<T, n> &aVector)
{
for (unsigned int i = 0; i < n; i++)
{
data[i] = aVector.data[i];
}
}
Vector<T, n>(const T arr[n])
{
for (unsigned int i = 0; i < n; i++)
{
data[i] = arr[i];
}
}
T& operator[](unsigned int i);
const T& operator[](unsigned int i) const;
Vector<T, n>& operator=(const Vector<T, n> &aVector);
void normalise();
T data[n];
};
I also have operators (+, *, etc.) declared outside the class, as well as a couple of other classes.
Here's the thing though. For vectors of length 2, 3, 4 I'd like to have a constructor (or a function) that takes x,y (for Vec2), x,y,z or x,y,z,w as parameters.
However, it seems that you can't make specialised constructors for this purpose. How should I proceed in that case ? Do I have to completely specialise three cases ? Wouldn't that imply that I have to rewrite chunks of code ?
I also have a similar Matrix class ( Matrix), and I'm pretty sure I'll need some constructors for rotation, translation, scaling, etc. I'm assuming I'll need to overcome a similar problem.
If you see
I also have operators (+, *, etc.) declared outside the class, as well as a couple of other functions (dot, cross, etc.).
Here's the thing though. For vectors of length 2, 3, 4 I'd like to have a constructor (or a function) that takes x,y (for Vec2), x,y,z or x,y,z,w as parameters.
However, it seems that you can't make specialised constructors for this purpose. How should I proceed in that case ? Do I have to completely specialise three cases ? Wouldn't that imply that I have to rewrite chunks of code ?
I also have a similar Matrix class ( Matrix), and I'm pretty sure I'll need some constructors for rotation, translation, scaling, etc. I'm assuming I'll need to overcome a similar problem.
If you see anything in the code that seems wrong to you, feel free to point it out by the way.
EDIT : In case I was not clear enough, the arrays are meant to be one-dimensional, and all of its components are of the same type. The specialisations are for arrays with 2, 3 and 4 elements.
You may utilize a variadic template:
#include <chrono>
#include <future>
#include <iostream>
#include <stdexcept>
template<typename T, unsigned int n>
struct Vector
{
// Note: We need x and y:
// The default (in the question) is a constructor taking a single argument.
template <typename ... Args>
Vector(T x, T y, Args ... args)
{
static_assert(sizeof ... (Args) == n - 2, "Invalid number of arguments");
auto initializer_list = { x, y, std::forward<Args>(args)... };
std::copy(initializer_list.begin(), initializer_list.end(), data);
}
T data[n];
};
template<typename T, unsigned int n>
void print(const Vector<T, n>& v) {
for(unsigned i = 0; i < n; ++i)
std::cout << v.data[i] << ' ';
std::cout << '\n';
}
int main()
{
Vector<int, 2> v2(1, 2);
Vector<int, 3> v3(1, 2, 3);
Vector<int, 4> v4(1, 2, 3, 4);
print(v2);
print(v3);
print(v4);
// Invalid number of arguments
// Vector<int, 3> e2(1, 2);
// Invalid number of arguments
// Vector<int, 3> e4(1, 2, 3, 4);
return 0;
}