Сбой вычета аргумента шаблона и несоответствие параметров и параметров функции
Рассмотрим следующую программу:
template <class T> struct A { using X = typename T::X; };
template <class T, typename A<T>::X* = nullptr> void f(T, int);
void f(...);
template <class T> void g(T, int, typename A<T>::X* = nullptr); // #
void g(...);
int main() {
// f(0, nullptr); // error
g(0, nullptr); // ok
}
g(0, nullptr)
компилирует пока f(0, nullptr)
нет (проверено под GCC багажник и Clang багажник на Godbolt). Кажется, что во время процесса вывода аргумента шаблона #
компилятор не инстанцирует A<int>
когда он находит аргумент nullptr
не соответствует параметру int
, Где стандарт определяет это поведение?
2 ответа
Это CWG1391:
Если вывод выполняется успешно для всех параметров, которые содержат параметры шаблона, которые участвуют в выводе аргументов шаблона, и все аргументы шаблона явно указываются, выводятся или получаются из аргументов шаблона по умолчанию, оставшиеся параметры затем сравниваются с соответствующими аргументами. Для каждого оставшегося параметра
P
с типом, который не зависел перед заменой каких-либо явно заданных аргументов шаблона, если соответствующий аргументA
не может быть неявно преобразовано вP
, вычет не удается.
Возможно, что вас укусила DR # 1844. В [temp.deduct]/8 говорится:
Если подстановка приводит к недопустимому типу или выражению, вывод типа завершается неудачей. Недопустимый тип или выражение - это тип, который был бы неправильно сформирован, с необходимостью диагностики, если он записан с использованием замещенных аргументов. [Примечание: если диагностика не требуется, программа все еще не работает. Проверка доступа выполняется как часть процесса замены. - примечание конца] Только недопустимые типы и выражения в непосредственном контексте типа функции, ее типов параметров шаблона и его явного спецификатора могут привести к ошибке вывода. [Примечание: замена на типы и выражения может привести к таким эффектам, как создание экземпляров специализаций шаблонов классов и / или специализаций шаблонов функций, генерация неявно определенных функций и т. Д. Такие эффекты находятся не в "непосредственном контексте" и могут В результате программа будет плохо сформирована. - конец примечания]
Проблема здесь в том, что "непосредственный контекст" на самом деле не имеет определения, что приводит к расхождению между компиляторами.