I'm trying to create classes for mathematical vectors in various dimensions, and since they have much in common I created a templated base class with the vectors size as the template parameter. I'm subclassing because I want different constructors (e.g. Vec2f(float x, float y)
, Vec3f(float x, float y, float z)
) and additional functions like the cross product for 3 dimensional vectors.
My Problem: What should operator+
in the baseclass return? If it returns an instance of the baseclass then Vec3f + Vec3f
returns Vecnf
, but it should return Vec3f
. Can this be achieved somehow?
Here is a code example:
template <size_t n>
class Vecnf {
public:
Vecnf operator+(Vecnf const & vec) const {
return Vecnf(*this) += vec;
}
Vecnf & operator+=(Vecnf const & vec) {
for (int i = 0; i < n; ++i) {
elements[i] += vec.elements[i];
}
return *this;
}
protected:
std::array<float, n> elements;
};
class Vec3f : public Vecnf<3> {
public:
Vec3f(float x = 0.0f, float y = 0.0f, float z = 0.0f);
Vec3f crossProd(Vec3f const & vec);
};
With this implementation, the following:
Vec3f a, b;
Vec3f c = a + b;
gives the compile time error
error: conversion from 'Vecnf<3u>' to non-scalar type 'Vec3f' requested
I'm using TDM GCC version 4.8.1 on Windows 8 Pro. I'm using c++11, so your solution can use it as well, but since I don't think it's crucial I haven't flagged the question with it. Thank you in advance :)
You could make the constructor a variadic template, thereby solving your first problem and eliminating the need to even use inheritance:
template <size_t n>
class Vecnf
{
std::array<float, n> elements;
public:
template <typename ... Args>
Vecnf(Args ... args):
elements {{static_cast<float>(args)...}}
{}
// other methods, operators etc...
};
Now you can make typedef
's for the commonly used sizes if you like:
typedef Vecnf<3> Vec3f;
In my opinion, you could even improve this by adding another template parameter for the type you want to store in the array. It could default to float
of course.
Also, it shouldn't be too hard to implement the cross-product in a generic way...