Проблема заключается в том, что параметр типа шаблона T
находится в невыгруженном контексте и не может быть выведен. Чтобы сделать это вычет, вы можете сделать это:
template<typename T>
T operator+(T iter, unsigned k)
{ ... }
Обратите внимание, что эта перегрузка потенциально может принести много вреда, поскольку T
не ограничивается значением std::list<T>::iterator
. SFINAE может помочь:
template<typename T, typename = std::enable_if_t<
std::is_same_v<T, typename std::list<
typename std::iterator_traits<T>::value_type>::iterator>>>
T operator+(T iter, unsigned k)
{ ... }
Добавление.
Вопрос, почему operator+<int>(q, 1);
терпит неудачу, более тонкий. Во-первых, цитата из The Standard, [temp.arg.explicit] / 8 (см. Также пример там):
Но когда используется шаблон функции с явными аргументами шаблона, вызов не имеет правильной синтаксической формы , если в точке вызова не отображается шаблон функции с этим именем . Если такого имени не видно, вызов синтаксически не правильно сформирован и поиск по аргументам не применяется. Если какое-то такое имя является видимым, применяется поиск, зависящий от аргумента, и дополнительные шаблоны функций могут быть найдены в других пространствах имен.
У нас здесь есть такой шаблон функции, это наш operator+
. Следовательно, ADL пытается найти operator+<int>
в std::
. Однако компиляция завершается неудачно, когда для некоторого шаблона operator+
создается экземпляр <int>
. Какой из них и как он не работает, зависит от конкретной реализации библиотеки std.
Например, gcc 8.1 пытается создать экземпляр
template<class _Iterator> constexpr
std::move_iterator<_IteratorL> std::operator+(
typename std::move_iterator<_IteratorL>::difference_type,
const std::move_iterator<_IteratorL>&)
[with _Iterator = int]
и терпит неудачу где-то внутри с
error: no type named 'reference' in 'struct std::iterator_traits<int>'
...
Если мы отключим ADL, он будет работать как положено:
::operator+<int>(q, 1);
или
(operator+<int>)(q, 1);