I am creating a templated matrix multiplication function where the returned matrix is a different size than the left-hand-side matrix. In that function I need to access a protected member of the matrix to be returned, but I get compiler error C2248: cannot access protected member. I believe this occurs because the template arguments are different sizes.
template<typename T, std::size_t r, std::size_t c>
struct Matrix
{
template<std::size_t c2>
Matrix<T, r, c2> operator*(const Matrix<T, c, c2>& rhs);
protected:
int test;
};
template<typename T, std::size_t r, std::size_t c>
template<std::size_t c2>
Matrix<T, r, c2> Matrix<T, r, c>::operator*(const Matrix<T, c, c2>& rhs)
{
Matrix<T, r, c2> retMat;
retMat.test;
return retMat;
}
I tried friending the operator*()
multiplication function:
...
protected:
int test;
template<std::size_t c2>
friend Matrix<T, r, c> Matrix<T, r, c2>::operator*(const Matrix<T, c2, c>& rhs);
};
but I get:
error C2245: non-existent member function Matrix<T,r,c>::operator * specified as friend (member function signature does not match any overload)
How can I access the protected variable in a Matrix
with different sized template parameter arguments?
cannot access protected member. I believe this occurs because the template arguments are different sizes.
Exactly: Matrix<int, 2, 3>
is a different type from (by example) Matrix<int, 3, 4>
; so inside a method of Matrix<int, 2, 3>
you can't access the test
member of Matrix<int, 3, 4>
.
I tried friending the
operator*()
multiplication function
It's the right way but you forgot an important element: a friend
function isn't a method of the class; it's a normal function.
If you implement operator*()
as method of a class (the wrong way for many reasons), it needs only an explicit parameter (the operand on the right of *
) because the other element (the operand on the left of *
) is, implicitly, the *this
element.
But when you implement operator*()
as a function (friend
to the class or not), there isn't the implicit *this
element; so the function needs two parameters.
So is wrong your
template<std::size_t c2>
friend Matrix<T, r, c> Matrix<T, r, c2>::operator*(const Matrix<T, c2, c>& rhs);
because receive only a parameter and isn't a Matrix<T, r, c2>::
.
The correct way to solve this problem (IMHO) is a function (not method) as follows
template <typename T, std::size_t D1, std::size_t D2, std::size_t D3>
Matrix<T, D1, D3> operator* (Matrix<T, D1, D2> const & m1,
Matrix<T, D2, D3> const & m2)
{
Matrix<T, D1, D3> retMat;
retMat.test = m1.test + m2.test;
return retMat;
}
that has to be friend to Matrix<T, D1, D2>
, Matrix<T, D2, D3>
and Matrix<T, D1, D3>
.
You can be temped to define it inside the class
template <typename T, std::size_t R, std::size_t C>
struct Matrix
{
protected:
T test;
template <typename U, std::size_t D1, std::size_t D2, std::size_t D3>
friend Matrix<U, D1, D3> operator* (Matrix<U, D1, D2> const & m1,
Matrix<U, D2, D3> const & m2)
{
Matrix<T, D1, D3> retMat;
retMat.test = m1.test + m2.test;
return retMat;
}
};
but this is wrong because cause a multiple definition of the same function in different classes.
So I suggest of declare (but not define) the operator*()
friend
inside the class
template <typename T, std::size_t R, std::size_t C>
struct Matrix
{
protected:
T test;
template <typename U, std::size_t D1, std::size_t D2, std::size_t D3>
friend Matrix<U, D1, D3> operator* (Matrix<U, D1, D2> const & m1,
Matrix<U, D2, D3> const & m2);
};
and define it outside.
The following if a full working example
#include <type_traits>
template <typename T, std::size_t R, std::size_t C>
struct Matrix
{
protected:
T test;
template <typename U, std::size_t D1, std::size_t D2, std::size_t D3>
friend Matrix<U, D1, D3> operator* (Matrix<U, D1, D2> const & m1,
Matrix<U, D2, D3> const & m2);
};
template <typename T, std::size_t D1, std::size_t D2, std::size_t D3>
Matrix<T, D1, D3> operator* (Matrix<T, D1, D2> const & m1,
Matrix<T, D2, D3> const & m2)
{
Matrix<T, D1, D3> retMat;
retMat.test = m1.test + m2.test;
return retMat;
}
int main ()
{
Matrix<long, 2U, 3U> a;
Matrix<long, 3U, 4U> b;
auto c { a * b };
static_assert( std::is_same<decltype(c), Matrix<long, 2U, 4U>>{}, "!" );
}