简体   繁体   中英

Overloading templated class binary operator*

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

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM