У меня есть класс по шаблону typename T
, Он содержит функцию,
template <typename T, size_t a>
myClass<T,a> operator+(myClass<T,a> lhs, const T& rhs) {
return lhs += rhs;
}
myClass<T,a> myClass<T,a>::operator+=(const T& rhs) {
// Do addition, depends on 'a'.
return *this;
}
Когда я называю это с, например,
myClass<double, 2> myObj_double_2(constructor args);
myObj_double_2 = myObj_double_2 + 5.2;
У меня нет никакой проблемы.
Если я однако позвоню
myObj_double_2 = myObj_double_2 + 5;
Затем компилятор выдает мне сообщение вроде — No match for 'operator+' (operand types are 'myClass<double, 2ul>' and 'int'). Candidates are ... note: deduced conflicting types for parameter 'const T' ('double' and 'int')
,
Могу ли я написать код для передачи дополнительных типов, которые имеют преобразование в T
(поскольку, например, double (5) является допустимым вызовом конструктора)?
Когда вы используете вывод аргумента шаблона, все вычеты для одного параметра шаблона должны иметь так же результат.
В вашем случае два вычета для T
производить double
а также int
, которые не совпадают, и поэтому вычет не удается.
Что вы можете сделать, это только использовать один аргумент функции для вывода аргумента шаблона, и сделать другой undeduced:
template <typename T, std::size_t A>
void foo(myClass<T, A> arg1, typename std::common_type<T>::type arg2);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Обратите внимание, что std::common_type<T>::type
по сути просто T
, но потому что тип arg2
теперь является зависимым типом (его имя отображается справа от ::
), это не выводится. Следовательно, только первый аргумент принимает участие в выводе и производит T = double
однозначно, а то второй параметр функции просто имеет тип double
и обычные преобразования происходят.
Как правило, вывод аргументов шаблона не пересекается ::
,
Компилятор по разрешению перегрузки не может найти подходящего кандидата для operator+
так как T
уже вычитается double
и буквальный 5
является целым числом Решение:
template <typename T1, typename T2, size_t a>
myClass<T1,a> operator+(myClass<T1,a> lhs, const T2& rhs) {
return lhs += T1(rhs);
}
У вас проблемы с вычетом типа шаблона.
Оба аргумента имеют «равное положение» при выводе значения T
и в этом случае два аргумента расходятся — один говорит T
должно быть int
другой говорит T
должно быть double
,
Правильный способ исправить это с помощью операторов Кенига.
Делать +=
а также +
и тому подобное friend
с вашего класса и реализовать встроенный:
template<class T, size_t a>
class myClass {
// etc
public:
friend myClass operator+(myClass lhs, const T& rhs) {
lhs += rhs;
return std::move(lhs);
}
friend myClass& operator+=(myClass& lhs, const T& rhs) {
// do addition, depends on `a`
return *this;
}
};
эта техника делает что-то странное. Это создает неtemplate
операторы, основанные на типе шаблона класса. Затем они обнаруживаются через ADL (поиск Кенига), когда вы вызываете +
или же +=
,
Вы получаете один из этих операторов для каждого экземпляра шаблона, но они не являются операторами шаблона, поэтому const T&
не выводится, и преобразование происходит, как ожидалось.