I have a class Matrix defined as template<class T, int m_rows, int m_cols = m_rows> class Matrix
and an overloaded operator of the type template <class V, int m_cols2> Matrix operator * (const Matrix<V,m_cols,m_cols2>& other)
. The idea is that, for example, if T is a complex and V is a double, the returning matrix should be of the type V (complex). How do I accomplish that in the code?
As of now I have
template <class V, int m_cols2>
Matrix operator * (const Matrix<V,m_cols,m_cols2>& other) const {
Matrix<T,m_rows,other.m_cols> res;
for (int i = 0; i < m_rows; ++i) {
for (int k = 0; k < other.m_rows; ++k) {
res[i][k] = 0;
for (int j = 0; j < m_cols; ++j) {
res[i][k] += m_matrix[i][j]*other[j][k];
}
}
}
return res;
}
But this automatically sets the matrix "res" to the type T. How can I tell that it should decide the type of res depending on the type hierarchy? For example complex > double > integer?
Thanks for your answers :)
I have no idea what to try:)
You could produce a matrix of a "common type":
// note: it's best not to call template parameters "m_something", because
// it creates confusion with data members of the class.
template <class OtherT, int OtherCols>
auto operator * (const Matrix<OtherT, Cols, OtherCols>& other) const
-> Matrix<std::common_type_t<T, OtherT>, Rows, OtherCols>> // trailing return type
{
// Avoid copying and pasing the return type with decltype.
// We could also use a deduced return type (just auto, no trailing -> ...),
// however, this wouldn't be SFINAE-friendly, i.e.: operator* gets
// instantiated even if there is no common type.
decltype(*this * other) result;
for // ...
return result;
}
If your complex
class is std::complex
, you can just use std::common_type
like in the above example. Otherwise you may have to specialize std:common_type<Complex, ...>
for your type to make it work.
This works because a double
is implicitly convertible to a std::complex<double>
, but not the other way around. It also works for int
and double
, i.e.
static_assert(std::is_same_v<double, std::common_type_t<int, double>>); // passes