Страницы

Поиск по вопросам

понедельник, 8 апреля 2019 г.

Перегрузка шаблонных операторов с разделением на описание и имплементацию

Есть класс Vector2, шаблонный.
template class Vector2 { public: // ... friend Vector2 operator*(ConstAddress> l_v, ConstAddress r_val); // ... }
// ...
template Vector2 operator*(ConstAddress> l_v, ConstAddress r_val) { return Vector2(l_v._x * r_val, l_v._y * r_val); }
ConstAddress - это моё собственное извращение, но в целом это то же самое, что и const T&
При попытке скомпилировать выдаёт ошибку
undefined reference to `operator*(Vector2 const&, float const&)'


Ответ

(Тема всплывает с заметной периодичностью.)
В качестве "друга" вы объявили нешаблонную функцию operator *. А определение ваше сделано для шаблона функции operator * - оно к вашему "другу" никакого отношения не имеет. Для оператора-друга вы не предоставили определения вообще, а именно его и пытается вызвать компилятор. Получается ошибка линковки.
(Если вы заставите компилятор вызвать именно шаблонную версию оператора, определенную после класса, то вы наткнетесь на другую ошибку: "другом" эта версия оператора не является и доступа к внутренним полям класса не имеет.)
Либо объявите шаблон функции в качестве "друга"
template class Vector2 { ... template friend Vector2 operator *(ConstAddress> l_v, ConstAddress r_val); ... };
template Vector2 operator *(ConstAddress> l_v, ConstAddress r_val) { return Vector2(l_v._x * r_val, l_v._y * r_val); } Либо перенесите определение вашего оператора прямо в тело класса - чтобы оно определяло правильную нешаблонную функцию. (Если я не ошибаюсь, синтаксиса для того, чтобы сделать это за пределами класса в С++ просто нет.)
template class Vector2 { ... friend Vector2 operator *(ConstAddress> l_v, ConstAddress r_val) { return Vector2(l_v._x * r_val, l_v._y * r_val); } ... };
В первом случае вы получите то, что я называю "ленивым" набором объявлений - все версии шаблонного оператора (для всех U) получат "дружбу" со всем версиями шаблонного класса (для всех T). Возможен также третий вариант - "неленивый" вариант шаблонного объявления, который несколько более громоздок, в котором "дружба" получится только между соответствующими (по шаблонному параметру) версиями шаблонного оператора и шаблонного класса. См. по ссылкам: Доступ к привату через friend Ссылка на неразрешенный внешний элемент

Комментариев нет:

Отправить комментарий