Нет оператора совпадения для 'operator *' в Matrix - PullRequest
0 голосов
/ 21 декабря 2011

У меня есть класс матрицы, как показано ниже:

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 data[M][N];
};

// ... the body is in header file too  ...//

Тело написало нормально, и все работает хорошо. Когда я определяю две матрицы, как показано ниже:

Matrix < 10, 10, int> m1;
Matrix < 10, 10, float> m2;

m1 + m2;  // OK
m1 * m2;  // error: no match for 'operator*' in 'm1 * m2'

Первый оператор '+' работает хорошо, потому что на нем выполнено неявное приведение . но для второго оператора '*' для разных типов значений возникает ошибка.

ошибка: нет совпадения для 'оператора *' в 'm1 * m2'

Есть идеи?!

UPDATE: Весь код находится в заголовочном файле. У меня нет проблем, кроме оператора '*'.

Что вы можете сказать об операторе «+»? Я знаю все о шаблонах / операторах / приведении ... но эта проблема похожа на ошибку для моего компилятора gcc !? Я написал оператор приведения, и этот оператор вызывает оператор «+», но я не знаю, почему он не работает для оператора «*»!

Ответы [ 2 ]

6 голосов
/ 21 декабря 2011

Проблема более или менее классическая.Разрешение перегрузки начинается с создания списка возможных функций;в этом случае функции с именем operator*.Для этого он добавляет все operator* функции, которые находятся в области видимости, в список и пытается создать экземпляр всех шаблонов функций, применяя дедукцию типа;если вывод типа завершается успешно, он добавляет экземпляр шаблона в список.(Шаблон функции - это , а не функция. Создание экземпляра шаблона функции - это функция.)

Правила для вывода типа шаблона отличаются от правил, используемых при разрешении перегрузки.В частности, рассматривается только очень маленький набор преобразований.Определяемые пользователем операторы преобразования не рассматриваются.В результате в m1 * m2 вычет типа для operator* завершается неудачно (поскольку для этого потребуется преобразование, которое не рассматривается).Таким образом, создание экземпляра шаблона функции не добавляется в список, и нет других operator*.

В более общем смысле: вы operator T2() не допустили бы вычитание типа, даже если бы это было разрешено;существует бесконечное количество конверсий, которые соответствуют operator*.На самом деле я подозреваю, что вы сделали это слишком общим;что вы хотите operator Matrix<M, N, T2>().(Не то, чтобы это помогло, но есть ситуации, в которых это может устранить неоднозначность.)

Вы могли бы заставить это работать, определив:

template<size_t P, tyepname OtherT>
Matrix<M, P, T> operator*( Matrix<N, P, T> const& rhs ) const;

, а затем выполнивконвертация внутри оператора *.(Я не пробовал и не уверен, но я думаю, что ваш существующий operator* следует считать «более специализированным», и, таким образом, его следует выбирать, когда вычитание типа будет успешным для обоих.)

Сказав этоЯ думаю, то, как ты это делаешь, - неправильный подход.Вы действительно хотите, чтобы типы возврата m1 * m2 и m2 * m1 были разными.Для начала, я бы потребовал, чтобы клиентский код сделал преобразование явным (что имеет место в вашем текущем коде);если вы хотите поддерживать неявные преобразования, я думаю, вам нужно сделать operator* глобальным, использовать какое-то простое метапрограммирование для определения правильного типа возвращаемого значения (т. е. заданных матриц long и unsigned,вы можете захотеть иметь тип возвращаемого значения unsigned long, поскольку это то, что арифметика смешанного типа с этими типами дает в противном случае), преобразовать обе стороны в целевой тип и выполнить арифметику для него.Много работы для того, что, вероятно, не очень важная или полезная функция.(Просто мое мнение, конечно. Если ваши клиенты действительно хотят смешанную арифметику и готовы за нее платить ...)

2 голосов
/ 21 декабря 2011

Неявное приведение является виновником в вашем примере (m1 * m1 работает).Хотя я не достаточно устойчив к языку, чтобы точно сказать вам, почему, я подозреваю, что комбинация метода шаблонного оператора * (который не определяет тип точно) и необходимого преобразования типов имеет слишком много неоднозначности.Компилятору сказано, что он может преобразовать вашу матрицу в любой тип, и что шаблонное семейство типов может быть допустимым аргументом для operator*. I будет иметь проблемы при определении, какой operator* вызывать из этих методов.Вставка static_cast в качестве m1 * static_cast< Matrix<10,10,int> >(m2) подтверждает это подозрение.

Библиотека Eigen - довольно зрелая и очень хорошая матричная библиотека, и они также не делают неявных скалярных преобразований.Вместо этого они использовали метод приведения:

template <typename Scalar> Matrix<M,N,Scalar> cast() const;

В вашем примере вы написали бы:

m1.cast<float>() * m2;  
...