Reputation: 321
I have the following template class:
template <class T>
class Matrix {
public:
Matrix(size_t rows, size_t columns, const T elements = 0);
// scalar multiplication
Matrix<T> operator*(const T& rhs){
Matrix<T> result(rows, columns);
for(size_t index = 0; index < rows * columns; ++index){
result.elements[index] = elements[index] * rhs;
}
return result;
}
Matrix <T> operator*(const T& lhs, const Matrix<T>& rhs);
const size_t rows;
const size_t columns;
private:
std::vector<T> elements;
};
and the following implementation of the operator* :
// scalar multiplication
template <class T>
Matrix<T> Matrix<T>::operator*(const T& lhs, const Matrix<T>& rhs){
Matrix<T> result(rhs.rows, rhs.columns);
for(size_t index = 0; index < rhs.rows * rhs.columns; ++index){
result.elements[index] = elements[index] * lhs;
}
return result;
}
when I try to compile clang says: error: overloaded 'operator*' must be a unary or binary operator (has 3 parameters)|
And I don't quite understand, what I am missing in this. In general template classes give me a hard time when it comes to overloading operators and I don't know why. There have been some posts on here on SO on this topic and I tried a few variations of the code but none of them worked.
Upvotes: 2
Views: 903
Reputation: 275405
The simple and reasonably efficient way to solve this problem is as follows:
Implement Matrix& operator *=(SomeType const&)
and similar operations first. These are mutating operations that change an instance of the class, then return a reference to *this
.
Implement other operations as inline friends in terms of *=
, where the lhs (usually) argument is taken by-value, modified and returned.
This tends to be really simple and quite often more efficient than starting with operator*
instead of operator*=
.
So you'll have:
template<class T, etc>
struct Matrix{
Matrix& operator*=(T const&);
Matrix& operator*=(Matrix const&);
Matrix& operator+=(Matrix const&);
which you implement traditionally. Then:
friend Matrix operator*(T const& t, Matrix m){ m*=t; return m; }
friend Matrix operator*(Matrix m, T const& t){ m*=t; return m; }
friend Matrix operator*(Matrix lhs, Matrix const& rhs){ lhs*=rhs; return lhs; }
friend Matrix operator+(Matrix lhs, Matrix const& rhs){ lhs+=rhs; return lhs; }
and now you only need to implement a few, traditional, methods.
These friend
operators are non-template inline non-method functions that are auto-generated for each template instance of Matrix.
Your immediate problem was your non-static operator actually took an implicit this
in addition to its two explicit parameters, and binary operators cannot take 3 arguments.
The complex and even more efficient solution involves a technique often called "expression templates". The disadvantage is that expression templates are more complex to write, and have a few points of fragility around the auto
keyword and similar situations.
As an example:
Matrix m = m1 * m2 + m3 * m4 + m5 + m6;
An expression template will do the above with only one allocation of the internal data of a matrix.
My above code will copy m1
, multiply the result by m2
. Then it will copy m3
, then multiply that by m4
. Then it will add up everything without making any additional copies. Finally, this result will be moved into m
.
So two matrices will be created instead of 1 in the expression template case.
A more-naive solution (like the OP's design) would create 5 Matrices instead of 2.
Upvotes: 3
Reputation: 2057
Your function is a member function. Member functions have a hidden parameter, the this pointer.
You either need to make your operator* a non-member function or you need to get rid of one of the arguments to your operator* function (which will then multiply the data in "this" with the data in the incoming Matrix<T>
.)
Upvotes: 2
Reputation: 172924
You're declaring Matrix <T> operator*(const T& lhs, const Matrix<T>& rhs);
as member function, which has an implicit parameter this
, that why compiler complains it "has 3 parameters".
You can make it a free template function,
template <class T>
class Matrix {
...
template <class Z>
friend Matrix<Z> operator*(const Z& lhs, const Matrix<Z>& rhs);
...
};
and
// scalar multiplication
template <class Z>
Matrix<Z> operator*(const Z& lhs, const Matrix<Z>& rhs){
Matrix<Z> result(rhs.rows, rhs.columns);
for(size_t index = 0; index < rhs.rows * rhs.columns; ++index){
result.elements[index] = elements[index] * lhs;
}
return result;
}
Upvotes: 2