Ошибка вывода аргумента шаблона при прохождении адреса типа const
template <typename T>
T go(T a, T *b){ T *t; return *t;}
int main() {
const int x = 10;
go(x, &x);
return 0;
}
Дает ошибку компилятора:
ошибка: нет подходящей функции для вызова "go (const int &, const int *)
Почему первым аргументом является ссылочный тип const int&
вместо const int
?
Чтобы исправить эту ошибку компиляции, я переопределил процесс вычитания компилятора, указав тип аргументов go<const int>(x, &x);
, но опять же зачем мне это нужно?
Ответы
Ответ 1
Это конфликт типа вычета. T
выводится как int
из первого аргумента и как const int
из второго аргумента. Следовательно, вывод типа не выполняется (и компилятор представляет сообщение, которое может или не может сделать основную причину ясными).
Если вы хотите, чтобы эта функция работала, не указывая явно аргумент шаблона, вы можете сделать так, чтобы только второй аргумент функции приводил к вычету:
template <class T>
struct NonDeduced { using type = T; }
template <class T>
T go(typename NonDeduced<T>::type a, T *b) { T *t; return *t; }
Таким образом, T
будет выводиться только из второго аргумента, а первый параметр будет использовать выводимый T
без изменений.
Ответ 2
Поскольку a
объявляется переданным по значению, то в вывод аргумента шаблона:
c) в противном случае, если A является cv-квалифицированным типом, то cv-квалификаторы верхнего уровня игнорируются для вывода:
Это означает, что для go(x, &x);
для первого аргумента x
параметр шаблона T
будет выведен как int
, а не const int
. Для второго аргумента T
будет выведено как const int
, потому что b
объявляется переданным указателем (и cv-квалификаторы на указываемом объекте зарезервированы, то же самое происходит для передачи по ссылке). Тогда вывод не выполняется.
BTW: clang дает для него довольно четкое сообщение:
prog.cc:4:3: примечание: шаблон кандидата игнорируется: выведено противоречивое типы для параметра 'T' ('int' vs. 'const int')