jeudi 17 août 2017

How to make a "variadic" vector like class

I am trying to make class that acts as multidimensional vector. It doesn't have to do anything fancy. I basically want to have a "container" class foo where I can access elements by foo[x][y][z]. Now I would also need similar classes for foo[x][y] and foo[x]. Which lead me to ponder about the following (more general) question, is there a way to make something like this where you can just initialize as foo A(a,b,c,...) for any n number of arguments and get a n-dimensional vector with elements accessible by [][][]...? Below the class I have for (in example) the four-dimensional case.

First the header

   #ifndef FCONTAINER_H
   #define FCONTAINER_H
   #include <iostream>
   using namespace std;

   class Fcontainer
   {
   private:
           unsigned dim1, dim2, dim3, dim4 ;
           double* data;
   public:
           Fcontainer(unsigned const dims1, unsigned const dims2, unsigned const dims3, unsigned const dims4);
           ~Fcontainer();

           Fcontainer(const Fcontainer& m);
           Fcontainer& operator= (const Fcontainer& m);

           double& operator() (unsigned const dim1, unsigned const dim2, unsigned const dim3, unsigned const dim4);
           double const& operator() (unsigned const dim1, unsigned const dim2, unsigned const dim3, unsigned const dim4) const;
    };
    #endif // FCONTAINER_H

Now the cpp:

  #include "fcontainer.hpp"

  Fcontainer::Fcontainer(unsigned const dims1, unsigned const dims2, unsigned const dims3, unsigned const dims4)
  {
       dim1 = dims1; dim2 = dims2; dim3 = dims3; dim4 = dims4;
       if (dims1 == 0 || dims2 == 0 || dims3 == 0 || dims4 == 0)
          throw std::invalid_argument("Container constructor has 0 size");
       data = new double[dims1 * dims2 * dims3 * dims4];
  }

  Fcontainer::~Fcontainer()
  {
      delete[] data;
  }

  double& Fcontainer::operator() (unsigned const dims1, unsigned const dims2, unsigned const dims3, unsigned const dims4)
  {
       if (dims1 >= dim1 || dims2 >= dim2 || dims3 >= dim3 || dims4 >= dim4)
           throw std::invalid_argument("Container subscript out of bounds");
       return data[dims1*dim2*dims3*dim4 + dims2*dim3*dim4 + dim3*dim4 + dims4];
  }

  double const& Fcontainer::operator() (unsigned const dims1, unsigned const dims2, unsigned const dims3, unsigned const dims4) const
  {
     if(dims1 >= dim1 || dims2 >= dim2 || dims3 >= dim3 || dims4 >= dim4)
         throw std::invalid_argument("Container subscript out of bounds");
      return data[dims1*dim2*dims3*dim4 + dims2*dim3*dim4 + dim3*dim4 + dims4];
  }

So I want to expand this to an arbitrary amount of dimensions. I suppose it will take something along the lines of a variadic template or an std::initializer_list but I am not clear on how to approach this( for this problem).

Aucun commentaire:

Enregistrer un commentaire