Самостоятельное введение
Привет всем, я невинный компилятор.
Первый звонок
test(a, b); // works
В этом вызове тип аргумента A
. Позвольте мне сначала рассмотреть первую перегрузку:
template <class T>
void test(T, T);
Easy. T = A
.
Теперь рассмотрим второе:
template <class T>
void test(Wrapper<T>, Wrapper<T>);
Хм ... что? Wrapper<T>
для A
? Мне нужно создать экземпляр Wrapper<T>
для каждого возможного типа T
в мире, чтобы убедиться, что параметр типа Wrapper<T>
, который может быть специализированным, не может быть инициализирован с аргументом типа A
? Ну ... я не думаю, что я собираюсь это сделать ...
Следовательно, я не буду создавать никаких экземпляров Wrapper<T>
. Я выберу первую перегрузку.
Второй звонок
test<A>(a, b); // doesn't work
test<A>
? Ага, мне не нужно делать дедукцию. Позвольте мне проверить две перегрузки.
template <class T>
void test(T, T);
T = A
. Теперь замените & mdash; подпись (A, A)
. Совершенная.
template <class T>
void test(Wrapper<T>, Wrapper<T>);
T = A
. Теперь субт ... Подожди, я никогда не создавал Wrapper<A>
? Я не могу заменить тогда. Как я могу узнать, будет ли это жизнеспособной перегрузкой для вызова? Ну, я должен сначала создать его экземпляр. (создание экземпляра) Подождите ...
using type = typename T::type;
A::type
? Ошибка!
Вернуться к Л.Ф.
Привет всем, я Л.Ф. Давайте рассмотрим, что сделал компилятор.
Был ли компилятор достаточно невинным? Соответствовал ли он (она?) Стандарту?
@ YSC указал, что [temp.over] / 1 говорит:
Когда пишется вызов функции или шаблона функции
(явно или неявно используя операторную нотацию), шаблон
удержание аргумента ([temp.deduct]) и проверка любого явного
аргументы шаблона ([temp.arg]) выполняются для каждой функции
шаблон, чтобы найти значения аргумента шаблона (если есть), которые могут быть
используется с этим шаблоном функции для создания экземпляра шаблона функции
специализация, которая может быть вызвана с помощью аргументов вызова. Для каждого
шаблон функции, , если вывод аргумента и проверка успешны ,
аргументы шаблона (выведенные и / или явные) используются для
синтезировать объявление одного шаблона функции
специализация, которая добавляется к функциям-кандидатам
используется в разрешении перегрузки. Если для данного шаблона функции,
сбой вывода аргумента или шаблон синтезированной функции
специализация будет плохо сформирована, такая функция не будет добавлена к
набор функций-кандидатов для этого шаблона. полный набор
Функции-кандидаты включают в себя все синтезированные объявления и все
не шаблонных перегруженных функций с тем же именем.
Синтезированные объявления обрабатываются как любые другие функции в
остаток разрешения перегрузки, за исключением случаев, явно указанных в
[Over.match.best].
Отсутствие type
приводит к серьезной ошибке. Считайте https://stackoverflow.com/a/15261234. По сути, у нас есть два этапа, чтобы определить, является ли template<class T> void test(Wrapper<T>, Wrapper<T>)
желаемой перегрузкой:
Инстанцирование. В этом случае мы (полностью) создаем экземпляр Wrapper<A>
. На этом этапе using type = typename T::type;
проблематично, поскольку A::type
не существует. Проблемы, возникающие на этом этапе, являются серьезными ошибками.
Замена. Так как первая стадия уже терпит неудачу, эта стадия даже не достигнута в этом случае. Проблемы, возникающие на этом этапе, регулируются SFINAE.
Так что да, невинный компилятор поступил правильно.