I have a matrix class like below: - c++

template <size_t M, size_t N, typename T>
class Matrix
{
public:
Matrix<M, N, T> operator +(const Matrix<M, N, T>& B) const;
template <size_t P> Matrix<M,P,T> operator*(const Matrix<N, P, T>& B) const;
template <typename T2> operator T2() const;
private:
T __x[M][N];
};
The body has written fine, and everything works well. When I define two Matrices as below:
Matrix < 10, 10, int> m1;
Matrix < 10, 10, float> m2;
m1 + m2; // OK
m1 * m2; // error: no match for 'operator*' in 'm1 * m2'
The addition works well, because an implicit casting has performed on it, but for the multiplication of different value types, an error occurs.
error: no match for 'operator*' in 'm1 * m2'
Any idea ?!

This question has a similar problem. The reason for you error is that implicit conversions are not considered when deducing template arguments. Since your multiplication operator is a function-template, and you call without explicitly providing the parameter, the compiler tries to deduce the argument type and fails. To demonstrate, if you explicitly provide the parameter P, it compiles:
m1.operator*<10>(m2);
To fix the problem, you could make the value-type of the right-hand-side a template-argument too:
template <size_t P, typenmame T2>
Matrix<M,P,T> operator*(const Matrix<N, P, T2>& B) const;

Related

How to fix 'no match for ‘operator*’ (operand types are ‘Matrix<double, 2, 3>’ and ‘Matrix<double, 3, 2>’)' with templates

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

c++ operator-overloading for a template struct

I have a template struct "point as follows:
template<typename T>
struct point
{
T x, y, z;
template<typename T1>
inline point<T> operator*(const point<T1>& p) const // multiply by another point.
{
return point<T>{this->x*p.x, this->y*p.y, this->z*p.z};
}
template<typename T1>
inline point<T> operator*(const T1& v) const // multiply by constant from right side
{
return point<T>{this->x*v, this->y*v, this->z*v};
}
}
template<typename T1, typename T2>
inline point<T1> operator*(const T2& v, const point<T1>& p) // multiply by a constant from the left side.
{
return point<T1>{p.x*v, p.y*v, p.z*v};
}
The two operator overloading functions that declared as member functions, the first one is supposed to multiply by another point, and the other to multiply a point by a constant from the right side, where the one declared outside the struct is to do the same thing but from the left side.
And now when I go to compile the following code:
point<double> p1{1,2,3};
point<float> p2{1,2,3};
point<double> p3 = p1*p3;
The compiler calls the one declared outside the struct instead of the one declared as a member function, and produces and error:
error: cannot convert ‘point<double>’ to ‘float’ in initialization
return point<T1>{p.x*v, p.y*v, p.z*v};
And that makes sense, because the both arguments are template variables and can be interpreted as point variables. Now the second one can be only a point variable, but the first one can be anything!
To solve this I can go and write several copies of that function, when declaring the first argument once as int, float, double, long double .. et cetera. This works fine for me, but I'm still wondering if there is a better way to deal with this, and if I can write only one copy as above?
Do not unnecessarily overload operators as member functions,
follow the rules described here.
Having operator* for two point instances return the type of the left one does not make sense, in my opinion. Better consider both types in the deduction of the return type, since the function is defined as commutative.
template<typename T>
struct point
{
T x, y;
};
template<typename T1, typename T2>
auto operator*(const point<T1>& lhs, const point<T2>& rhs)
-> point<decltype(std::declval<T1>() * std::declval<T2>())>
{
return {lhs.x*rhs.x, lhs.y*rhs.y};
}
template<typename T1, typename T2>
point<T1> operator*(const point<T1>& p, const T2& v)
{
return {p.x*v, p.y*v};
}
template<typename T1, typename T2>
point<T1> operator*(const T2& v, const point<T1>& p)
{
return p * v;
}
Try to do the same with the overloads for multiplication by a scalar as an exercise.

templated function not found during compilation

I have a matrix class that supports operations with scalar values that I implemented using operator overloading. Since each overloaded operator function has the same body except for the operator being used, I decided to create a generic function that would accept a function along with the matrix and a scalar value to consolidate my code.
Here is the generic function and it being called from the overloaded addition operator function:
// Generic function to take care of matrix operations
template<typename T, typename F>
Matrix<T> scalar_operation(const Matrix<T> &a, const T b, F f) {
std::vector<std::vector<T> > new_els = a.elements;
typename std::vector<std::vector<T> >::iterator it = new_els.begin();
typename std::vector<T>::iterator it_in;
for (; it != new_els.end(); ++it) {
it_in = it->begin();
for (; it_in != it->end(); ++it_in) {
*it_in = f(*it_in, b);
}
}
return Matrix<T>(new_els);
}
// Add scalar to all values in Matrix
template<typename T>
Matrix<T> operator+(const Matrix<T> &a, const T b) {
return scalar_operation(a, b, std::plus<T>());
}
And here are the functions declared in the matrix class:
template<class T>
class Matrix {
template<typename F>
friend Matrix<T> scalar_operation(const Matrix<T> &a, const T b, F f);
friend Matrix<T> operator+<>(const Matrix<T> &a, const T b);
friend Matrix<T> operator-<>(const Matrix<T> &a, const T b);
friend Matrix<T> operator*<>(const Matrix<T> &a, const T b);
friend Matrix<T> operator/<>(const Matrix<T> &a, const T b);
When I implemented the overloaded operator functions separately, they worked, but with this implementation, I get the following compiler error:
Undefined symbols for architecture x86_64:
"Matrix<float> scalar_operation<std::__1::plus<float> >(Matrix<float> const&, float, std::__1::plus<float>)", referenced from:
Matrix<float> operator+<float>(Matrix<float> const&, float) in matrix_test-3188cd.o
ld: symbol(s) not found for architecture x86_64
I imagine my error is related to the Matrix<float> scalar_operation<std::__1::plus<float> >( line because it looks like the linker is searching for a function with this header, which is slightly different from how it's declared in my file, but I've tried modifying my declaration and it throws additional errors.
Why am I getting this error and how can I fix it? Thanks!
EDIT: To clear up some confusion, all the code has been implemented in the header file since it is a templated class. There is no corresponding .cpp file.
The code has the following problem: class Matrix declares the friend function friend template<typename F> scalar_operation(...) (yes, friend keyword not only states the private access, it also declares a function), but there is no such function in outer scope. There is only the template<typename T, typename F> scalar_operation, that does not satisfy friend Matrix's declaration. Why? Let's try to pseudocode instantiations that can be made with float and std::plus<float> (return values and arguments omitted for shortness):
friend scalar_operation<std::plus<float>>(...)
and
scalar_operation<float, std::plus<float>>(...).
As we can see they are different. So during compilation we have no problem: we have proper friend scalar_operation declaration that satisfies calling convention inside operator+. But no definitions of such declaration can be made, and we get a problem while linking. The solution is a proper friend declaration:
template<typename TT, typename F>
friend Matrix<TT> scalar_operation(const Matrix<TT> &, const TT, F);

Express preference in case of ambiguous templated functions

Given the following code:
struct Zero{};
template<typename T>
Zero operator*(const Zero& zero, const T& other){return Zero();}
struct Identity{};
template<typename T>
T operator*(const T& other, const Identity& id){return T();}
Now, I want to use this code like this:
Zero z;
Identity id;
int i = 5;
z * i; // ok
i * id; // ok
z * id; //error: ambiguity in function resolution
The compiler will not be able to resolve the operator in the last line, because both functions could be used. In fact in this case I do not care which function is used, since they have the same functionality. In both cases Zero() will be returned as expected.
My Question: How can I express that in this case any of the functions are ok to use?
Just add one more overload (which is not a template whatsoever):
Zero operator*(const Zero& other, const Identity& id){return Zero();}
Just use SFINAE to remove the first template from consideration if T is Identity:
template<typename T> auto operator*(const Zero& zero, const T& other)
-> typename std::enable_if<!std::is_same<T, Identity>::value, Zero>::value
{return {};}

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.