VN VNA
VN VNA

Reputation: 117

C++ template class specialization constructor

I want to create a generic Vector class like this Vector<int Dimension, typename Type>. And this is my code:

template <int Dimension, typename Type>
class Vector
{
public:
  Vector() 
    : _data {} 
  {}
  Vector(const std::array<Type, Dimension>& init)
    : _data {init}
  {}
  ...
protected:
 std::array<Type, Dimension> _data;
};

With that declaration, i can initialize my vector with a std::array.

Vector<3, float> vec({1.0f, 2.0f, 3.0f});
// or like this
Vector<3, float> vec = {{1.0f, 2.0f, 3.0f}};

But now i want my vector has a better constructor for some common vector type like Vec1, Vec2, Vec3, ... I have tried to create a recursion template class to add an additional constructor for each of them:

template <typename Type>
class Vector<3, Type>
{
public:
  Vector(const Type& x, const Type& y, const Type& z)
    : _data {x, y, z}
  {}
};

But when i compile my program i received this error:

error C3861: '_data': identifier not found

My questtion are:

PS: Sorry if my English is hard to understand 🤦‍♀️.

Upvotes: 2

Views: 193

Answers (1)

n. m. could be an AI
n. m. could be an AI

Reputation: 119877

Why?

There is no recursion here. Vector<3, Type> is a wholly independent thing, unrelated to the generic Vector<Dimension, Type>. It does not contain any _data or anything else that the main template contains.

How?

You don't need recursion or specialisation here, you need a forwarding constructor.

  template <int Dimension, typename Type>
  class Vector
  {
    public:
      template <typename ... T>
      Vector(T&& ... t) 
        : _data{std::forward<T>(t)...} {}
  
    protected:
      std::array<Type, Dimension> _data;
  };

This is the only constructor you need. It basically says "initialise Vector with whatever you can initialise _data". So you can have:

Vector<4, int> v4(1,2,3,4);
Vector<2, int> v2{1,2};

std::array<float, 3> u3 = {1.0, 2.0, 3.0};
Vector<3, float> v3{u3};

Vector<5, float> v5;

Is this all?

No. Perhaps you do need to add some functionality to Vector<3,Type> which is not present in the main template. In this case you can use inheritance.

  • Rename your Vector class template to VectorBase

  • Create a new Vector class template that inherits from ``VectorBase` and uses its constructor, and does nothing more:

    template <int Dimension, typename Type>
    class Vector : public VectorBase<Dimension, Type> {
       public:
           using VectorBase<Dimension, Type>::VectorBase;
    };
    
  • Now you can specialise Vector and add functionality to it. You need to repeat the using declaration in every specialisation, but that's not too much boilerplate.

Upvotes: 2

Related Questions