Подтвердить что ты не робот

Почему моя шаблонная функция не поддерживает "int" до "T", где "T" = "double"?

У меня есть шаблон с шаблоном 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) является допустимым вызовом конструктора)?

4b9b3361

Ответ 1

Когда вы используете вывод аргумента шаблона, все вычеты для одного параметра шаблона должны иметь одинаковый результат.

В вашем случае два вывода для 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, и происходят обычные преобразования.

Как правило, вычет аргумента шаблона не пересекает ::.

Ответ 2

Компилятор при разрешении перегрузки не может найти нужного кандидата для 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);
}

Ответ 3

У вас возникают проблемы с вычитанием типа шаблона.

При определении значения T оба аргумента даются "равным стоям", и в этом случае два аргумента не согласны - один говорит, что T должен быть int, а другой - T должен быть double.

Правильный способ исправить это с помощью операторов Koenig.

Сделайте += и + и т.д. 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 (поиск Koenig) при вызове + или +=.

Вы получаете один из этих операторов для каждого экземпляра шаблона, но они не являются операторами шаблонов, поэтому const T& не выводится, и преобразование происходит, как ожидалось.