I'm working on a generic matrix class.
I to overload the + function, so that when is do :
matrix = scalar * matrix
matrix = matrix * scalar
matrix = matrix * matrix
Tried to do it like that (function overloading):
Is it a right way to do it ?
template<class T>
class Matrix
{
std::vector< std::vector<T> > mat;
size_t rows , cols;
public:
Matrix(){}
Matrix(const std::string){ }
Matrix(const size_t r, const size_t c, const std::vector<T> v){ }
Matrix(const Matrix& other);
Matrix<T> operator=(const Matrix<T> &other) { }
Matrix<T> operator+(const Matrix<T> &other) const{}
friend Matrix<T> operator*(const T &mat, const Matrix<T> &scalar) { }
friend Matrix<T> operator*(const Matrix<T> &mat, const T &scalar) { }
friend Matrix<T> operator*(const Matrix<T> &mat, const Matrix<T> &other) { }
Also I'll be glad to know if there is some problems with my declarations.
Thanks for any help.
If you want to overload operator* to allow
matrix = scalar * matrix
matrix = matrix * scalar
matrix = matrix * matrix
you need to define these three operator overloads as functions in the namespace surrounding the matrix class:
class Matrix { ... };
Matrix operator*(Scalar const& s, Matrix const& m) { ... }
Matrix operator*(Matrix const& m, Scalar const& s) { ... }
Matrix operator*(Matrix const& m1, Matrix const& m2) { ... }
In your case, you declared the operators as friend functions inside the class, which does the same because it actually declares free functions and makes them friends. It depends on the implementation if the friend is actually necessary. If not, I'd move them outside the class for clarity, but keep in mind that you will need template<typename T> then. Concerning the rest of the code, there is nothing that is visibly broken, but it is only an excerpt of the real code anyway.
Looking at the question, had a alternate idea.
matrix = scalar * matrix
matrix = matrix * scalar
matrix = matrix * matrix
alternative way would be to use the function objects and pass them to the matrix class, so that function objects could handle the algorithm specifics...This allows you to add some more later on if needed.
Operator chaining would also be handy in the above code,hence, return by reference for overloaded operators.
Related
For trivial types, compilers can optimize arithmetic expressions into a new expression, with the same result, that requires less instructions in order to compute it. For example, if a, b are int, then the expression int c = a * a + b * a would be computed as (a + b) * a, which saves an instruction.
Is there a way to tell the compiler to perform this optimization for custom types? E.g., if A, B are matrices, then computing A*A + A*B would be factored as A*(A+B) (at compile time), which saves about n2 operations during runtime.
First note, A*A + A*B != (A+B)*A for matrices, not even close. It's A*(A+B) and that's not the same as matrix multiplication is not commutative. That said, what you're asking for, as a conceptual thing, is feasible.
This is not a complete answer, just a heads up. As #JerryJeremiah correctly wrote, you might use expression templates for this. First for your matrix class, instead of operators implementing evaluation of expressions, you return an unevaluated context: (here I show value scemantics, of course, you might implement it using references/pointers)
template<typename LHS, typename RHS, char op>
struct OperatorContext {
static constexpr char operator = op;
const LHS lhs;
const RHS rhs;
};
// inside Matrix {
template<typename LHS, typename RHS, char op>
friend auto operator+(const Matrix& lhs, OperatorContext<LHS, RHS, op>& rhs) {
return OperatorContext<Matrix, OperatorContext<LHS, RHS, op>, '+'>{lhs, rhs};
}
template<typename LHS, typename RHS, char op>
friend auto operator+(OperatorContext<LHS, RHS, op>& lhs, const Matrix& rhs) {
return OperatorContext<Matrix, OperatorContext<LHS, RHS, op>, '+'>{lhs, rhs};
}
friend auto operator+(const Matrix& lhs, const Matrix& rhs) {
return OperatorContext<Matrix, Matrix, '+'>{lhs, rhs};
}
// similarly for other operators
// }
// furthermore, you need similar operators for 2 OperatorContext arguments
Then, you can implement assignment operator to Matrix from various OperatorContext<> versions. Here, you might do the optimization, as you have complete type info. Note that this only works until you assign to a variable. E.g.:
// inside Matrix {
Matrix& operator=(OperatorContext<OperatorContext<Matrix, Matrix, '*'>, OperatorContext<Matrix, Matrix, '*', '+'> other) {
if (other.lhs.lhs == other.rhs.lhs) { // preferably compare-by-address
*this = other.lhs.lhs * (other.lhs.rhs + other.rhs.rhs)
} else {
*this = other.lhs.lhs * other.lhs.rhs + other.rhs.lhs * other.rhs.rhs;
}
return *this;
}
// }
I'm trying to implement a template based Matrix class in C++17. The class should override operator*() to allow formulations such as
Matrix<double, 2, 3> a = {{{3,2,1},{1,0,2}}};
Matrix<double, 3, 2> b = {{{1,2},{0,1},{4,0}}};
Matrix c = a * b;
but this is causing a compiler error.
no match for ‘operator*’ (operand types are ‘Matrix<double, 2, 3>’ and ‘Matrix<double, 3, 2>’)
43 | Matrix c = a * b;
| ~ ^ ~
| | |
| | Matrix<[...],3,2>
| Matrix<[...],2,3>
I know in principle Matrix a and b are completely different types but somehow I think it should be possible because both, 2nd and 3rd, template arguments are of type size_t.
template <typename T, size_t nbRows, size_t nbColumns>
class Matrix {
public:
Matrix(std::vector<std::vector<T>> &&vector) {
assert(vector.size() == nbRows);
assert(vector.front().size() == nbColumns);
auto matrixIter = matrix.begin();
for(auto && row : vector) {
std::copy_n(std::make_move_iterator(row.begin()), nbColumns, matrixIter);
std::advance(matrixIter, nbColumns);
}
}
friend inline Matrix operator*(Matrix lhs, const Matrix &rhs) {
// Compute the product of lhs and rhs
return lhs;
}
private:
std::array<T, nbRows * nbColumns> matrix;
};
Your operator* applies to Matrix<A, B> and Matrix<A, B> (same types) but not Matrix<A, B> and Matrix<B, A> (different types). Instead of defining the operator within the class template, do it as a free function outside of the class template like so:
template<typename T, size_t LhsRows, size_t LhsColumns, size_t RhsRows, size_t RhsColumns>
auto operator*(const Matrix<T, LhsRows, LhsColumns>& lhs, const Matrix<T, RhsRows, RhsColumns>& rhs)
{
static_assert(LhsColumns == RhsRows, "unrelated matrix sizes");
// ...
}
This way you can apply the operator to two different instantiations of the Matrix class template.
Make the operator* function a template, that takes other sets of "rows" and "columns":
template<size_t rows1, size_t cols1, size_t rows2, size_t cols2>
friend inline Matrix operator*(Matrix<T, rows1, cols1> lhs, const Matrix<T, rows2, cols2> &rhs) {
// Compute the product of lhs and rhs
return lhs;
}
Or if you only want to handle the reverse (switching "rows" and "columns") then use that for the classes in the argument list:
friend inline Matrix operator*(Matrix<T, nbRows, nbColumns> lhs, const Matrix<T, nbColumns, nbRows> &rhs) {
// Compute the product of lhs and rhs
return lhs;
}
The two arguments for your operator have different types. You need to introduce a template argument for the number of columns in the second argument and the number of columns in the resulting type. You can then replace Matrix with the proper type for each use :
template<size_t nbOther>
friend inline Matrix<T, nbRows, nbOther> operator*(
const Matrix<T, nbRows, nbColumns> & lhs,
const Matrix<T, nbColumns, nbOther> &rhs)
{
// Do math
}
Since matrix multiplication requires that the inner dimension are the same, you only need 1 additional template argument. Any other information you need is already provided by the class template arguments.
As a final note, operator* should not return lhs. Normally the operator*= variant of the operator would return a reference to lhs but you won't be able to implement it here since the operation would need to change the type of lhs which is not possible in c++. The return value will be a distinct matrix of type Matrix<T, nbRows, nbOther> which generally wont be the same type as either of the parameters.
As you said a & b have different types Matrix<double, 2, 3> and Matrix<double, 3, 2>
so your operator overload will become something like this
friend inline Matrix<double, 2, 3> operator*(Matrix<double, 2, 3> lhs, const Matrix<double, 2, 3> &rhs) {
// Compute the product of lhs and rhs
return lhs;
}
that is the reason of why the compiler cannot find the proper operator overload for your class, so in order to solve this you should add an overload where rhs columns are equal to lhs rows but rhs has a different rows count
template<size_t nbColsR>
friend inline Matrix<T, nbRows, nbColsR> operator*(Matrix lhs, const Matrix<T, nbColumns, nbColsR> &rhs) {
// Compute the product of lhs and rhs
return lhs;
}
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.
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.
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;
}
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>.)
I have written a matrix class. I have overloaded the operator+, so that the user can write: matrix + 2. I would like the user to also write: 2 + matrix.
For the standard format (i.e. the object invoking 2) I have written a standard operator overloading function. It works.
template<typename T>
Matrix<T> Matrix<T>::operator+(const T& rhs) const
{
Matrix result(rows, cols, 0.0);
for (unsigned i = 0; i < rows; ++i)
{
for (unsigned j = 0; j < cols; ++j)
{
result(i,j) = (*this)(i, j) + rhs;
}
}
return result;
}
Now for the other order (i.e. 2 + matrix), I have written the friend function:
// Friend Functions that allow the user to write expressions in a different order
template<typename T>
friend Matrix<T> operator+(const T& type, const Matrix<T>& matrix);
and implementation as:
template<typename T>
Matrix<T> operator+(const T& type, const Matrix<T>& matrix)
{
return matrix + type;
}
When I try to write 2 + matrix (in main()), I get some errors.
I have always had problems using friend functions with generic classes and frankly, I have never understood why it never works for me.
Could someone please explain what I am doing wrong here?
Errors I get:
IntelliSense: no operator "+" matches these operands operand types are: int + Matrix
Severity Code Description Project File Line Error C2244 'Matrix::operator +': unable to match function definition to an existing declaration
It looks like it's just a template deduction error; that is to say that your compiler can't deduce the proper function based on the templated friend function.
Since your friend function is a simple function, you could just declare it in your class/header and the compiler should be able to deduce it properly (as well as possibly inline it if optimizations are turned on); just declare the friend function in your header like such:
friend Matrix operator+(const T& type, const Matrix& matrix)
{
return matrix + type;
}
You don't need to specify the template keyword since it's within your template specialized class.
Hope that can help.
You can fix the problem simply by changing the member function to const.
template<typename T>
Matrix<T> Matrix<T>::operator+(const T& rhs) const
{
...
}
I have a Matrix class and it has overloaded * operators for scalar and matrix multiplications.
template <class T> class Matrix
{
public:
// ...
Matrix operator*(T scalar) const;
// ...
}
// ...
template <class T>
Matrix<T> Matrix<T>::operator*(T RightScalar) const
{
Matrix<T> ResultMatrix(m_unRowSize, m_unColSize);
for (uint64_t i=0; i<m_unRowSize; i++)
{
for (uint64_t j=0; j<m_unColSize; j++)
{
ResultMatrix(i, j) = TheMatrix[m_unColSize * i + j] * RightScalar;
}
}
return ResultMatrix;
}
// ...
I can multiply a matrix object with a scalar from right side without any problem:
Matrix<double> X(3, 3, /* ... */); // Define a 3x3 matrix and initialize its contents
Matrix<double> Y; // Define an output matrix
Y = X * 10.0; // Do the linear operation
But, how do I multiply it from left side same way?
Matrix<double> X(3, 3, /* ... */);
Matrix<double> Y;
Y = 10.0 * X;
In arithmetic, it is a common notation to write constants on the left side when doing multiplication. I would like to obey this rule to make my code more readable.
Is it possible to implement this in C++?
If it is possible, how do I modify the class method in my code?
Member functions are matched by their left-hand-side argument which is the this-pointer. Since native types can't have member functions, you have to add right-multiplication with user-defined types through non-member functions (and also for other types you don't have write-access to).
template<typename T>
Matrix<T> operator*(T const& scalar, Matrix<T> rhs)
{
// scalar multiplication is commutative: s M = M s
return rhs *= scalar; // calls rhs.operator*=(scalar);
}
NOTE: I wrote the above non-member operator* implemented in terms of a member operator*=. It is recommended to write all multiplications as non-member functions, and use a member operator*= to implement these multiplications with a lhs Matrix element.
This will a) keep the class interface minimal, and b) prevent hidden conversions. E.g. you could have a Matrix class that is implicitly convertible to scalar if the dimensions are 1x1, and these conversions could silently happen if you don't provide a separate overload that is a direct match.
template<typename T>
Matrix<T> operator*(Matrix<T> lhs, T const& scalar)
{
return lhs *= scalar; // calls lhs.operator*=(scalar);
}
template<typename T>
Matrix<T> operator*(Matrix<T> lhs, Matrix<T> const& rhs)
{
return lhs *= rhs; // calls lhs.operator*=(rhs);
}
Notice on how the lhs Matrix is a copy and not a reference. This allows the compiler to make optimizations such as copy elision / move semantics. Also note that the return type of these operators is Matrix<T> and not const Matrix<T> which was recommended in some old C++ books, but which prevents move semantics in C++11.
// class member
template<typename T>
Matrix<T>& Matrix<T>::operator*=(Matrix<T> const& rhs)
{
// your implementation
return *this;
}
// class member
template<typename T>
Matrix<T>& Matrix<T>::operator*=(T const& scalar)
{
// your implementation
return *this;
}
You'll need a non-member function for that:
template <typename T>
Matrix<T> operator*(T scalar, Matrix<T> const & matrix) {
return matrix * scalar;
}
Non-member operator overloads allow you to specify any type on either side, while member overloads always get the object on the left-hand side.