Разрешение перегрузки шаблона функции с двумя пакетами параметров
Рассмотрим следующий код:
#include<iostream>
template<class..., class... T>
int f(T...) { return 1; }
template<class... T>
int f(T...) { return 2; }
int main()
{
std::cout << f(1);
}
Компилирует и печатает 1
на gcc 8.2, но не может скомпилировать на clang 7 из-за вызова f(1)
быть неоднозначным
Если вызов заменен на f()
оба компилятора не в состоянии компилировать, утверждая, что вызов был неоднозначным.
Если пакет параметров class... T
заменяются простым параметром class T
(а также T...
с T
), оба компилятора также утверждают неоднозначность.
Какой из компиляторов соответствует стандарту в первом примере? Я предполагаю, что это сводится к определенным правилам частичного упорядочения для шаблонов функций, или это уже плохо сформировано, чтобы использовать пакет двойных параметров таким образом?
Редактировать:
Насколько я понимаю, двойной пакет сам по себе не плохо сформирован, потому что [temp.param] 17.1/15 в моем чтении явно допускает это, если второй пакет выводится из аргументов функции, что, по-видимому, имеет место из-за T...
пакет параметров функции.
Также возможно явно указать аргументы первого пакета параметров, но не вторые, и поэтому не всегда (после вычета аргументов шаблона) по крайней мере один пакет параметров пуст. Я не уверен, делает ли это программу плохо сформированной, потому что я не знаю, как читать, например, [temp.res] 17.7/8.3 в этом контексте.
Кажется, что и gcc, и clang подходят для самого пакета с двумя параметрами, например, когда устранена перегрузка шаблона второй функции, оба компилятора печатают 1
, Но это может быть случай плохо сформированный, никакой диагностики не требуется.
Кроме того, я предполагаю, что с вычетом аргумента шаблона класса шаблон вариативного класса мог бы иметь определенный шаблон конструктора с переменными параметрами, что подразумевало бы наличие кандидата-конструктора, аналогичного моему примеру с пакетом с двумя параметрами, и насколько я понимаю, такое же разрешение перегрузки и вычет аргументов шаблона требуют место в этом контексте. Этот вопрос был мотивирован другим вопросом с такой настройкой: вывод шаблона Variadic завершается неудачно с gcc 8.2, компилируется с помощью clang и msvc. См. Также обсуждение этого вопроса: Руководства по выводу и шаблоны классов с переменным числом элементов с помощью конструкторов шаблонов с переменным числом аргументов - несоответствующие длины пакета аргументов
Теперь я также нашел ответ на вопрос " Руководство по дедукции и вариационные шаблоны", который, как я предполагаю, подразумевает, что gcc неверен, и вызов следует считать неоднозначным, но я хотел бы, чтобы он подтвердил, что это применимо и здесь. Я также хотел бы поподробнее приветствовать рассуждения, потому что правила частичного упорядочения шаблона функции кажутся мне очень неясными.
1 ответ
Здесь есть два вопроса.
Во-первых, [temp.deduct.partial] / 12 (я также цитирую пример, поскольку он похож на ваш) говорит:
В большинстве случаев вывод не выполняется, если не все параметры шаблона имеют значения, но для целей частичного упорядочения параметр шаблона может остаться без значения при условии, что он не используется в типах, используемых для частичного упорядочения. [Примечание. Параметр шаблона, используемый в невзаимодействующем контексте, считается использованным. - примечание конца] [Пример:
template <class T> T f(int); // #1 template <class T, class U> T f(U); // #2 void g() { f<int>(1); // calls #1 }
- конец примера]
Типы, используемые для частичного заказа: T...
в соответствии с [temp.deduct.partial] / 3:
Типы, используемые для определения порядка, зависят от контекста, в котором выполняется частичное упорядочение:
В контексте вызова функции используемые типы - это те типы параметров функции, для которых вызов функции имеет аргументы.
...
Итак, первый неназванный пакет параметров шаблона class...
не влияет на результат частичного упорядочения. Поскольку нет никаких других различий для двух шаблонов функций, ни один не является более специализированным, чем другой, что приводит к неоднозначному вызову.
Это может быть связано с ошибкой 49505 в GCC.
Во-вторых, хотя второй шаблон функции не существует, вызов все равно должен быть некорректным. Согласно [temp.arg.explicit] / 3:
... Конечный пакет параметров шаблона, не выведенный иначе, будет выведен в пустую последовательность аргументов шаблона...
Только конечный пакет параметров шаблона может быть выведен в пустой пакет, в то время как первый неназванный пакет параметров шаблона class...
не является завершающим пакетом параметров шаблона.
И GCC ( ошибка 69623), и Clang ( ошибка 26435) имеют ошибки для этой проблемы.