У меня есть следующий шаблон класса:
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;
};
и следующая реализация оператора *:
// 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;
}
когда я пытаюсь собрать Clang говорит: error: overloaded 'operator*' must be a unary or binary operator (has 3 parameters)|
И я не совсем понимаю, чего мне в этом не хватает. В общем, классы шаблонов доставляют мне трудности, когда дело доходит до перегрузки операторов, и я не знаю почему. Здесь, на SO, было несколько сообщений на эту тему, и я попробовал несколько вариантов кода, но ни один из них не работал.
Простой и достаточно эффективный способ решения этой проблемы заключается в следующем:
Воплощать в жизнь Matrix& operator *=(SomeType const&)
и аналогичные операции в первую очередь. Это мутирует операции, которые изменяют экземпляр класса, а затем возвращают ссылку на *this
,
Реализуйте другие операции как действующие друзья с точки зрения *=
где аргумент lhs (обычно) принимается по значению, изменяется и возвращается.
Это, как правило, очень просто и часто более эффективно, чем начинать с operator*
вместо operator*=
,
Итак, вы будете иметь:
template<class T, etc>
struct Matrix{
Matrix& operator*=(T const&);
Matrix& operator*=(Matrix const&);
Matrix& operator+=(Matrix const&);
который вы реализуете традиционно. Затем:
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; }
и теперь вам нужно всего лишь реализовать несколько традиционных методов.
Эти friend
операторы являются встроенными не шаблонными встроенными функциями, которые генерируются автоматически для каждого экземпляра шаблона Matrix.
Ваша непосредственная проблема заключалась в том, что ваш нестатический оператор фактически принял неявный this
в дополнение к его двум явным параметрам, и бинарные операторы не могут принимать 3 аргумента.
Сложное и даже более эффективное решение включает технику, часто называемую «шаблоны выражений». Недостатком является то, что шаблоны выражений более сложны для написания и имеют несколько точек хрупкости по всему auto
Ключевое слово и подобные ситуации.
В качестве примера:
Matrix m = m1 * m2 + m3 * m4 + m5 + m6;
Выражение шаблон будет делать выше только с одним распределением внутренних данных матрицы.
Мой код выше скопирует m1
, умножьте результат на m2
, Тогда это будет копировать m3
затем умножьте это на m4
, Тогда он будет складывать все, не делая дополнительных копий. Наконец, этот результат будет перенесен в m
,
Таким образом, две матрицы будут созданы вместо 1 в случае шаблона выражения.
Более наивное решение (например, дизайн ОП) создаст 5 матриц вместо 2.
Вы декларируете Matrix <T> operator*(const T& lhs, const Matrix<T>& rhs);
как функция-член, которая имеет неявный параметр this
Вот почему компилятор жалуется, что «имеет 3 параметра».
Вы можете сделать это бесплатной функцией шаблона,
template <class T>
class Matrix {
...
template <class Z>
friend Matrix<Z> operator*(const Z& lhs, const Matrix<Z>& rhs);
...
};
а также
// 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;
}
Ваша функция является функцией-членом. Функции-члены имеют скрытый параметр, указатель this.
Вы должны либо сделать свой оператор * не являющейся членом функции, либо вам нужно избавиться от одного из аргументов функции вашего оператора * (которая затем умножит данные в «this» на данные во входящей матрице<T>
.)