Question

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 :)

Was it helpful?

Solution

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...

OTHER TIPS

You can just define an operator+ on vec3f that does what you want it to. It can have a differing return type to vecnf's as long as it's a subtype of it and it will still override it.

Better solution is what @JorenHeit introduced; that actually is what you wanted, together with two typedefs. This solution is c++03 compatible though, and his isn't.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top