Reputation: 434
I'm writing a 2D matrix template to learn templates and some C++11 features.
Wrote the following header:
template <class T, unsigned int Rows, unsigned int Columns>
class Matrix2D
{
private:
array<array<T,Columns>, Rows> m_Matrix;
public:
Matrix2D() {}
array<T,Columns>& operator[](unsigned int row) { return m_Matrix[row]; } ;
const array<T,Columns>& operator[](unsigned int row) const { return m_Matrix[row]; } ;
friend Matrix2D operator+ <> (const Matrix2D &lhs, const Matrix2D &rhs);
friend Matrix2D operator* <> (const Matrix2D &lhs, const Matrix2D &rhs);
};
The operator+
works fine - I have an implementation, it compiles, links, and stepped through with the debugger.
Problem is with operator*
, for which I get the compilation error
1>...\matrix2d.h(18): error C2143: syntax error : missing ';' before '<'
1>...\matrix2d.h(19) : see reference to class template instantiation 'Matrix2D<T,Rows,Columns>' being compiled
There's no line of code trying to use the operator, so it's the definition itself which is wrong, I just don't understand why.
Can anyone help?
EDIT: (added from comment)
template <class T, unsigned int Rows, unsigned int Columns>
Matrix2D<T, Rows, Columns> operator+ (const Matrix2D<T, Rows, Columns> &lhs, const Matrix2D<T, Rows, Columns> &rhs)
{
Matrix2D<T, Rows, Columns> addResult;
for (unsigned int i = 0; i < Rows; i++)
for (unsigned int j = 0; j < Columns; j++)
addResult[i][j] = lhs[i][j] + rhs[i][j];
return addResult;
}
template <class T, unsigned int Rows, unsigned int Columns>
Matrix2D<T, Rows, Columns> operator* (const Matrix2D<T, lRows, lColumns> &lhs, const Matrix2D<T, rRows, rColumns> &rhs)
{
Matrix2D<T, lRows, rColumns> mulResult;
for(unsigned int i = 0; i < lRows; i++)
for(unsigned int j = 0; j < rColumns; j++)
for (unsigned int k = 0; k < lColumns; k++)
mulResult[i][k] += lhs[i][k] * rhs[k][j];
return addResult;
}
Upvotes: 1
Views: 279
Reputation: 42594
You cannot friend a specialization of an undeclared template function. Of course, declaring the operators before defining the class template will require you to forward declare it as well:
template <class T, unsigned int Rows, unsigned int Columns>
class Matrix2D;
template <class T, unsigned int Rows, unsigned int Columns>
Matrix2D<T, Rows, Columns>
operator+ (const Matrix2D<T, Rows, Columns> &lhs, const Matrix2D<T, Rows, Columns> &rhs);
template <class T, unsigned int Rows, unsigned int Columns>
Matrix2D<T, Rows, Columns>
operator* (const Matrix2D<T, Rows, Columns> &lhs, const Matrix2D<T, Rows, Columns> &rhs);
template <class T, unsigned int Rows, unsigned int Columns>
class Matrix2D
{
private:
array<array<T,Columns>, Rows> m_Matrix;
public:
Matrix2D() {}
array<T,Columns>& operator[](unsigned int row) { return m_Matrix[row]; }
const array<T,Columns>& operator[](unsigned int row) const { return m_Matrix[row]; }
friend Matrix2D operator+ <> (const Matrix2D &lhs, const Matrix2D &rhs);
friend Matrix2D operator* <> (const Matrix2D &lhs, const Matrix2D &rhs);
};
alternatively, you could take the easy way and define separate operator functions for each specialization of Matrix2D
:
template <class T, unsigned int Rows, unsigned int Columns>
class Matrix2D
{
private:
array<array<T,Columns>, Rows> m_Matrix;
public:
Matrix2D() {}
array<T,Columns>& operator[](unsigned int row) { return m_Matrix[row]; }
const array<T,Columns>& operator[](unsigned int row) const { return m_Matrix[row]; }
friend Matrix2D operator+ (const Matrix2D &lhs, const Matrix2D &rhs) {
// do stuff that adds.
}
friend Matrix2D operator* (const Matrix2D &lhs, const Matrix2D &rhs) {
// do stuff that multiplies.
}
};
which I would probably use for the simpler overall syntax.
EDIT: Proper multiplication of non-square matrices means that the operator*
function would in fact need to be friends of three different specializations of Matrix2D
: the type of the left operand, right operand, and result. I think the first approach herein would become untenable. You should either friend all specializations of operator*
:
template <class T, unsigned int Rows, unsigned int Columns>
class Matrix2D
{
// ...
template <typename U, typename V, unsigned Rows, unsigned Common, unsigned Columns>
friend Matrix2D<decltype(std::declval<U>()+std::declval<V>()), Rows, Columns>
operator * (const Matrix2D<U, Rows, Common>&,
const Matrix2D<V, Common, Columns>&);
};
or simply make the data public (probably the best approach for a "collection-of-data" class anyhow).
Upvotes: 2
Reputation: 218343
In:
template <class T, unsigned int Rows, unsigned int Columns>
class Matrix2D
{
// ...
friend Matrix2D operator* <> (const Matrix2D &lhs, const Matrix2D &rhs);
};
Matrix2D
refer in fact to Matrix2D<T, Rows, Columns>
.
And your operator *
should be
template <T, unsigned Rows1, unsigned int Common, unsigned int Column>
Matrix2D<T, Row1, Column> operator* (const Matrix2D<T, Row1, Common>& lhs, const Matrix2D<T, Common, Column>& rhs);
Upvotes: 1