user796530
user796530

Reputation:

Different member function for Different Non-Type Template Parameters

I have a Vector class and a Matrix class. I would like to implicitly convert a Vector class to a Matrix class using a = operator. The classes are defined as shown below.

template <unsigned int dim>
class Vector {
public:
  std::array<double, dim> x;
};

template <unsigned int nrow, unsigned int ncol>
class Matrix {
public:
  std::array<Vector<ncol>, nrow> x;

  auto& operator=(Vector<ncol> v)
  {
    x.fill(v);
    return *this;
  }
};

int main()
{
  Vector<2> vec1;
  vec1.x[0] = 1;
  vec1.x[1] = 2;

  Matrix<1, 2> mat1;
  mat1 = vec1;

  std::cout << mat1.x[0].x[0] << std::endl;
  std::cout << mat1.x[0].x[1] << std::endl;
}

And this works correctly. However, I want to introduce another operator= which should work as show below.

auto& operator=(Vector<nrow> v)
{
  for(unsigned int row=0; row < nrow; ++row){
    x[row].x[0] = v[row];
  }
  return *this;
}

However, since the overloads instantiate to the same signature (for cases where nrow=ncol), I am not sure how to go about designing such a method. In specific, I wonder if it possible to define the second method only if nrow!=ncol.

I have tried using std::enable_if by defining two type

using nrow_t = std::integral_constant<unsigned int,nrow>;
using ncol_t = std::integral_constant<unsigned int,ncol>;

and then using std::is_same, but I am not sure how to proceed further.

Upvotes: 1

Views: 94

Answers (1)

NathanOliver
NathanOliver

Reputation: 180650

This might be a case where using a named function would be a lot easier. It will convey exactly what is going on and not surprise anyone. That said you can use something like this

template <unsigned int nrow, unsigned int ncol>
class Matrix {
public:
    std::array<Vector<ncol>, nrow> x;

    template<unsigned int cols,
             std::enable_if_t<cols == ncol || (cols == ncol && ncol == nrow)>* = nullptr>
    auto& operator=(Vector<cols> v)
    {
        x.fill(v);
        return *this;
    }
    template<unsigned int rows,
             std::enable_if_t<rows == nrow && nrow != ncol>* = nullptr>
    auto& operator=(Vector<rows> v)
    {
        for(unsigned int row=0; row < nrow; ++row){
            x[row].x[0] = v[row];
        }
        return *this;
    }
};

For the first overload we enable_if when cols == ncol || (cols == ncol && ncol == nrow) is true. That will happen when it has the correct amount as the columns or the rows and columns are the same and it has the correct amount of columns. The second overload uses rows == nrow && nrow != ncol and will only be active when the rows and columns are not the same and when the row amount matches.

Upvotes: 2

Related Questions