У меня есть классы 3x3 Matrix
и 3x1 Vector
. У меня есть два оператора умножения; один для умножения матрицы на скаляр, другой для умножения матрицы на векторный объект. Оператор матрично-скалярного умножения является членом класса Matrix
, а оператор матрично-векторного умножения является глобальным.
#include <initializer_list>
#include <array>
template <class T>
class Matrix
{
public:
Matrix(std::initializer_list<T> List);
Matrix() : Matrix({0,0,0,0,0,0,0,0,0}) {}
template <class S> // THE COMPILER TRIES TO USE
Matrix<T> operator*(const S & Scalar); // THIS OPERATOR IN BOTH CASES.
const T & operator()(size_t i, size_t j) const;
private:
static constexpr size_t SIZE = 3;
static constexpr size_t AREA = SIZE * SIZE;
std::array<T, AREA> E;
};
template <class T>
Matrix<T>::Matrix(std::initializer_list<T> List)
{
if (List.size() != AREA) throw("Error!");
for (size_t i=0; i<AREA; i++)
{
E[i] = *(List.begin() + i);
}
}
template <class T>
const T & Matrix<T>::operator()(size_t i, size_t j) const
{
return E[SIZE * j + i];
}
template <class T>
template <class S>
Matrix<T> Matrix<T>::operator*(const S & Scalar)
{
const T ScalarT = static_cast<T>(Scalar);
Matrix<T> Result;
for (size_t i=0; i<AREA; i++)
{
Result.E[i] = E[i] * ScalarT;
}
return Result;
}
template <class T>
class Vector
{
public:
Vector(std::initializer_list<T> List);
Vector() : Vector({0,0,0}) {};
const T & operator()(size_t i) const;
T & operator()(size_t i);
private:
static constexpr size_t SIZE = 3;
std::array<T, SIZE> E;
};
template <class T>
Vector<T>::Vector(std::initializer_list<T> List)
{
if (List.size() != SIZE) throw("Error!");
for (size_t i=0; i<SIZE; i++)
{
E[i] = *(List.begin() + i);
}
}
template <class T>
const T & Vector<T>::operator()(size_t i) const
{
return E[i];
}
template <class T>
T & Vector<T>::operator()(size_t i)
{
return E[i];
}
template <class T> // THE COMPILER NEVER TRIES USING THIS GLOBAL OPERATOR.
Vector<T> operator*(const Matrix<T> & Mat, const Vector<T> & Vec)
{
Vector<T> Result;
Result(0) = Mat(0,0) * Vec(0) + Mat(0,1) * Vec(1) + Mat(0,2) * Vec(2);
Result(1) = Mat(1,0) * Vec(0) + Mat(1,1) * Vec(1) + Mat(1,2) * Vec(2);
Result(2) = Mat(2,0) * Vec(0) + Mat(2,1) * Vec(1) + Mat(2,2) * Vec(2);
return Result;
}
int wmain(int argc, wchar_t *argv[]/*, wchar_t *envp[]*/)
{
Matrix<float> Mat1({2, 0, 0,
0, 2, 0,
0, 0, 2});
Vector<float> Vec1({1,
2,
3});
Matrix<float> Mat2 = Mat1 * 2; // Matrix-Scalar Multiplication
Vector<float> Vec2 = Mat1 * Vec1; // Matrix-Vector Multiplication
return 0;
}
Проблема в том, что когда я пытаюсь выполнить умножение матрицы на вектор, компилятор выбирает и пытается использовать оператор умножения матрицы на скаляр и выдает ошибку компилятора.
Если я удалю оператор матрично-скалярного умножения и строку, где я его использую, программа запустится успешно. И наоборот, если я удалю оператор умножения матрицы на вектор, он снова запустится успешно. Они просто не ладят. И когда он запускается (в любом случае), он делает все расчеты правильно.
Что здесь происходит не так?
Компилятор и IDE: Microsoft Visual Studio 2015 Community Edition
template<class S>
...(const S&)
соответствует всем объектам . Это не означает только скалярные типы или что-то в этом роде. - person M.M   schedule 08.03.2016operator*
. (Это, вероятно, не решит вашу проблему, но может устранить некоторые отвлекающие факторы или мешающие факторы) - person M.M   schedule 08.03.2016Matrix<T> operator*(const S & Scalar) const
. - person n. 1.8e9-where's-my-share m.   schedule 08.03.2016T
вместо другого параметра шаблона. - person Simon Kraemer   schedule 08.03.2016T
для своего оператора-члена? - person Simon Kraemer   schedule 08.03.2016const Vector<T>&
предпочтительным по сравнению сconst S&
, ничего не усложняется в операторах-членах и операторах, не являющихся членами, по крайней мере, здесь членoperator*
, вероятно, должен быть квалифицирован как const, хотя clang по-прежнему находит это неоднозначным - person Piotr Skotnicki   schedule 08.03.2016T
, чтобы решить вашу проблему. Он также должен быть менее подвержен ошибкам. Проходя например. указатель не имеет никакого смысла, но работает с вашим текущим подходом. Но также позаботьтесь о таких вещах, как const-correctity и других вещах, упомянутых в комментариях выше. - person Simon Kraemer   schedule 08.03.2016return *this;
в операторе участника ;-) - person Simon Kraemer   schedule 08.03.2016T
используется дважды, дляMatrix
иVector
, поэтому clang может подумать, что ни один из них не является более специализированным, чем другой, отсюда и двусмысленность.Matrix<float>
более специализирован, чемMatrix<T>
, точно так же, какconst Vector<T>&
более специализирован, чемconst S&
- person Piotr Skotnicki   schedule 08.03.2016operator*
глобальным и позволить вывестиT
изMatrix<T>
(как в версииVector<T>
) - person Piotr Skotnicki   schedule 08.03.2016Matrix<float>::operator*
илиMatrix<T>::operator*
? - person n. 1.8e9-where's-my-share m.   schedule 08.03.2016Matrix<float>
, компилятор получает две перегрузки:template<class S> operator*(const Matrix<float>&, const S&)
иtemplate<class T> operator*(const Matrix<T>&, const Vector<T>&)
, то есть компилятор видитfloat
, так какMatrix<float>
является неявным параметром объекта. - person Piotr Skotnicki   schedule 08.03.2016