Overloading operators in C++ with template classes - c++

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

Related

Compile-time expression factoring for user-defined types

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

How to overload an operator with a friend function in a generic class?

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
{
...
}

template function overloading c++

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.

Multiplying an object with a constant from left side

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.

Templates and casting

I created a matrix class with templates:
template <typename T>
class Matrix
{
static_assert(std::is_arithmetic<T>::value,"");
public:
Matrix(size_t n_rows, size_t n_cols);
Matrix(size_t n_rows, size_t n_cols, const T& value);
// Functions
// Operators
Matrix<T>& operator*=(const T& value)
private:
size_t rows;
size_t cols;
std::vector<T> data;
};
I created the following two (external) operators to multiply my matrix with a number:
// Inner operator used by the externals ones
template <typename T>
inline Matrix<T>& Matrix<T>::operator*=(const T& value)
{
for(size_t i(0); i < data.size(); i++)
{
data[i] *= value;
}
return *this;
}
template <typename T>
inline Matrix<T> operator*(const T& value, const Matrix<T>& matrix)
{
Matrix<T> tmp(matrix);
return tmp *= value;
}
template <typename T>
inline Matrix<T> operator*(const Matrix<T>& matrix, const T& value)
{
return value * matrix;
}
The problem is that if I declared the matrix as a double, I can multiply the matrix only by doubles and so on...
Matrix<double> m1(3,3,1.);
5. * m1; // Works
5 * m1; // Doesn't work (5 is an int and not a double)
How can I fix this behave? It is possible to let doubles be multiplied by others arithmetic types?
Sure, just allow two parameters to your templated free functions and member functions.
For example:
template <typename T> class Matrix {
/* ... */
template <typename U>
inline Matrix<T>& operator*=(const U& value)
{
for(size_t i(0); i < data.size(); i++)
{
data[i] *= value;
}
return *this;
}
};
template <typename T, typename U>
inline Matrix<T> operator*(const U& value, const Matrix<T>& matrix)
{
Matrix<T> tmp(matrix);
return tmp *= value;
}
This will trigger compiletime errors if you try to multiply your Matrix with something nonsensical, that is, if T*U is undefined.
Yes. Declare the function in the Matrix class as
template <typename T>
class Matrix
{
public:
/* ... */
template <typename S>
inline Matrix & operator*=( const S & value );
/* ... */
};
The definition looks like
template <typename T>
template <typename S>
inline Matrix<T>& Matrix<T>::operator*=(const S& value)
{
for(size_t i(0); i < data.size(); i++)
{
data[i] *= value;
}
return *this;
}
for the member function. You need to write template twice. A bit odd, but that's C++ syntax.
In case of the free functions you can write
template <typename T, typename S>
inline Matrix<T> operator*(const S& value, const Matrix<T> &mat)
{
Matrix<T> tmp(mat);
return tmp *= value;
}
The problem that you are seeing is that template type deduction requires a perfect match of all of the deduced types. In your case you have a template that takes a single type argument T that is both the scalar and the matrix types. When the compilers sees the operation: 5 * m1, it deduces T == int for the first argument but T == double for the second argument, and type deduction fails.
There are multiple approaches around this, as it has been suggested, you can add a second template argument:
template <typename T, typename S>
Matrix<T> operator*( Matrix<T> m, S scalar ) {
return m*=scalar;
}
[Note: both arguments by value, the second one because for arithmetic types it is more efficient and idiomatic to pass by value; the first one because by moving the copy to the interface of the function you allow the compiler to elide copies]. This approach is simple, but will generate one operator* for each combination of S and T in the program, even though the actual multiplication in operator*= is always performed on T.
Another approach would be to fix the type of the scalar that you want to multiply by, for example, make it double, generating only one operator* per T type that is multiplied:
template <typename T>
Matrix<T> operator*( Matrix<T> m, double scalar ) {
return m*=scalar;
}
In this approach there is a single operator*, the one taking a double as argument. As in the previous example, it might require two type conversions on the scalar (say you multiply Matrix<int> by 5, it will then convert 5 into a double, which will then be converted back to int to match the signature of operator*=.
The third approach is to create a non-templated function that takes your Matrix and another argument of the same type. This will be the closest to your original code, with the slight advantage that not being a template, it will allow conversions for the scalar argument. Theoretically you could define all such functions yourself manually:
Matrix<int> operator*( Matrix<int>, int ) { ... }
Matrix<double> operator*( Matrix<double>, double ) { ... }
But this becomes a maintenance problem very easily. Luckily, there is a feature in the language that allows for the definition of all those non-template functions generically. Although the syntax might not be the most natural. You just need to declare the free function as a friend of your template, and define it inside the class template definition:
template <typename T>
class Matrix {
// ...
friend Matrix operator*( Matrix m, T scalar ) { return m*=scalar; }
};
As we are inside the class template Matrix, we can use Matrix (without arguments) to refer to the current instantiation (Matrix<int>, Matrix<double...) [This might not seem obviously important, but it is, it is important to realize when Matrix refers to the template, and when it refers to the class generated from the template]. The second argument to the function is T. Again, this is not the generic T of the class template, but the current instantiating type (int, double...).
The language allows for the definition of a friend function inside the class that has the declaration, and that will define the function at namespace level, although the declaration will only be found through Argument Dependent Lookup.
Whenever you instantiate a particular instance of your template (say Matrix<int>) and call the operator, the compiler will generate the free function for you. Because the function is not templated, it will allow conversions on the arguments, and thus for Matrix<int> m it will allow you to call m * 5. by converting 5. into an int.