Умножение объекта с константой с левой стороны

у меня есть Matrix класс и он перегружен * операторы для скалярных и матричных умножений.

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

// ...

Я могу умножить матричный объект на скаляр с правой стороны без каких-либо проблем:

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

Но как мне умножить это с левой стороны таким же образом?

Matrix<double> X(3, 3, /* ... */);
Matrix<double> Y;
Y = 10.0 * X;

В арифметике это обычное обозначение для записи констант слева при выполнении умножения. Я хотел бы соблюдать это правило, чтобы сделать мой код более читабельным.

Возможно ли реализовать это в C ++?
Если это возможно, как я могу изменить метод класса в моем коде?

9

Решение

Функции-члены сопоставляются по их левому аргументу, который является указателем this. Поскольку нативные типы не могут иметь функции-члены, вы должны добавить умножение справа с пользовательскими типами через функции, не являющиеся членами (а также для других типов, к которым у вас нет прав записи).

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

НОТА: Я написал выше не член operator* осуществляется с точки зрения члена operator*=, Рекомендуется записывать все умножения как функции, не являющиеся членами, и использовать член operator*= реализовать эти умножения с элементом матрицы lhs.

Это а) сохранит интерфейс класса минимальным и б) предотвратит скрытые преобразования. Например. у вас может быть класс Matrix, который неявно преобразуется в скаляр, если размеры 1×1, и эти преобразования могут происходить без вывода сообщений, если вы не предоставите отдельную перегрузку, которая является прямым соответствием.

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

Обратите внимание, что матрица lhs является копией, а не ссылкой. Это позволяет компилятору оптимизировать, например, копировать семантику elision / move. Также обратите внимание, что тип возвращаемых данных операторов Matrix<T> и не const Matrix<T> что было рекомендовано в некоторых старых книгах по C ++, но препятствует семантике перемещения в 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;
}
10

Другие решения

Для этого вам понадобится функция, не являющаяся членом:

template <typename T>
Matrix<T> operator*(T scalar, Matrix<T> const & matrix) {
return matrix * scalar;
}

Перегруженные операторы, не являющиеся членами, позволяют указывать любой тип с любой стороны, в то время как перегрузки членов всегда получают объект с левой стороны.

8

По вопросам рекламы [email protected]