Get type of product of two different templates

Viewed 83

Consider the following struct:

template<typename R, unsigned short nCols, unsigned short nRows>
struct Matrix{
  std::array<std::array<R, nRows>, nCols> data;
  Matrix<R, nCols, nRows>(){
  }
}

Now I want to implement multiplication function, but that might change the type. For example, I could have a matrix of integers and multiply it with a float. Then the new matrix would of course be of the type float. How would I implement this? This doesn't work:

template<typename S>
Matrix<R*S, nRows, nCols> mul(const S& s){
  Matrix<R*S, nRows, nCols> result;
  for( unsigned short i = 0; i < nCols; ++i ){
    for( unsigned short j = 0; j < nRows; ++j ){
      result = data[i][j] * s;
    }
  }
  return result;
}

MWE:

template<typename R, unsigned short nCols, unsigned short nRows>
struct Matrix{
  std::array<std::array<R, nRows>, nCols> data;
  Matrix<R, nCols, nRows>(){
  }

  template<typename S>
  Matrix<R*S, nRows, nCols> mul(const S& s){
    Matrix<R*S, nRows, nCols> result;
    for( unsigned short i = 0; i < nCols; ++i ){
      for( unsigned short j = 0; j < nRows; ++j ){
        result = data[i][j] * s;
      }
    }
    return result;
  }
}

int main(){
    Matrix A<int, 2, 2> A;
    A.data[0][0] = 1;
    A.data[0][1] = 2;
    A.data[1][0] = 3;
    A.data[1][1] = 4;
    A.mul(3.141f);
    return 1;
}
1 Answers

You need to use decltype.

One possible option is:

decltype(std::declval<R>() * std::declval<S>())

For brevity, std::declval<R>() can be replaced with data[0][0].

The second operand can also be replaced with s.data[0][0] if you use trailing return type: auto mul(const S& s) -> decltype(...).


Alternatively, since R and S are probably default-constructible, you can get away with

decltype(R{} * S{})
Related