1

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;
}
11
  • What is the definition of operator*? Please, add it to the question. There is only the friend declaration in the question. Commented Jan 16, 2014 at 16:24
  • Compilation fails before reaching the definition, so I omitted it. Here it is, if it matters any 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; } Commented Jan 16, 2014 at 16:28
  • @UriRaz: you may edit your question instead of adding implementation in comment. Commented Jan 16, 2014 at 16:45
  • Could you post a complete example showing both the working operator+ and non-compilable operator*? In general, to friend a full specialization of some template (such as these operators), it (the template you're specializing) needs to be declared prior to this point. Commented Jan 16, 2014 at 16:48
  • 1
    OP's problem is the signature of operator * which take different size of matrices. Commented Jan 16, 2014 at 17:19

2 Answers 2

2

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).

Sign up to request clarification or add additional context in comments.

Comments

1

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);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.