Multiplying an object with a constant from left side
Asked Answered
D

2

9

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?

Daffi answered 23/1, 2013 at 14:45 Comment(1)
It is possible, but not with a class method.Cantatrice
B
12

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;
}
Buoyant answered 23/1, 2013 at 14:48 Comment(0)
F
10

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.

Fluent answered 23/1, 2013 at 14:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.