gcc против clang, msvc и icc: является ли этот вызов функции неоднозначным?
все компиляторы, которые я мог бы получить, согласны с тем, что это нормально:
template <typename Check, typename... T>
auto foo(Check, T...) -> void;
template <typename... T>
auto foo(int, T...) -> void;
int main()
{
foo(7, "");
}
однако следующий код (с ведущим параметром шаблона, который не может быть выведен из параметров функции) неоднозначен в соответствии с gcc:
template <typename X, typename Check, typename... T>
auto bar(Check, T...) -> void;
template <typename X, typename... T>
auto bar(int, T...) -> void;
int main()
{
bar<void>(7, ""); // ambiguous according to gcc
bar<void>(7); // just fine
}
С другой стороны, clang, msvc и icc вполне довольны этим.
какой компилятор правильно?
ссылки на соответствующие разделы стандарта предпочтительным.
2 ответов
описание того, как частичное упорядочение функций шаблона определено в пункте 14.5.6.2 [temp.функция.порядок] пункты 3-5 не составляют любое положение для параметров шаблона nondeduced. Например, вызов функции в следующем коде неоднозначно, хотя шаблон "очевидно" более специализирован, чем другой:
template <class T> T f(int); template <class T, class U> T f(U); void g() { f<int>(1); }
причина в том, что ни список параметров функции позволяет параметр шаблона
T
быть выведенным; оба вывода терпят неудачу, поэтому ни один шаблон является более специализированным, чем другие и вызов функции неоднозначен.
разрешение основной выпуск 214, к которому это было сведено, введено [temp.вычитать.partial] / 11:
в большинстве случаев, все параметры шаблона должны иметь значения для вычета на успех, но для частичного заказ цели параметр шаблона может оставаться без значения при условии, что он не используется в типах, используемых для частичного заказа.
по-видимому, реализация GCC этой формулировки глючит, как только пакеты вступают в игру.
IMHO я считаю, что GCC ошибается, и CLANG здесь правильный. Я попытаюсь обосновать свое требование ниже:
по стандарту §14.8.3 / P1 разрешение перегрузки [temp.конец] (Выделено Мной):
шаблон функции может быть перегружен либо (не шаблон) функции его имени или по (другим) шаблонам функций того же имя. Когда вызов этого имени записывается (явно или неявно с помощью оператор обозначения),вывод аргумента шаблона (14.8.2) и выполняется проверка любых явных аргументов шаблона (14.3) для каждого шаблона функции Найти значения аргументов шаблона (если any), который можно использовать с этим шаблоном функции для создания экземпляра специализация шаблона функции, которую можно вызвать с помощью вызова аргументы. Для каждого шаблона функции, если аргумент дедукции и проверка успешна, шаблон-аргументы (выведенные и / или явные) не использовать синтезировать объявление одного шаблона функции специализация, которая добавляется к функциям-кандидатам используется в разрешении перегрузки. If, для заданного шаблона функции, ошибка вывода аргумента или шаблон синтезированной функции специализация была бы плохо сформирована, такая функция не добавляется к набор функций-кандидатов для этого шаблона. Полный набор функции-кандидаты включают все синтезированные объявления и все из non-template перегруженные функции с тем же именем. Этот синтезированные объявления рассматриваются как любые другие функции в остальная часть разрешения перегрузки, за исключением явно отмеченного в 13.3.3.144
[пример:
template<class T> T max(T a, T b) { return a>b?a:b; } void f(int a, int b, char c, char d) { int m1 = max(a,b); // max(int a, int b) char m2 = max(c,d); // max(char a, char b) int m3 = max(a,c); // error: cannot generate max(int,char) }
144) параметры специализаций шаблонов функций содержат нет типов параметров шаблона. Набор преобразований, разрешенных для вывода аргументы ограничены, поскольку процесс вывода аргументов производит шаблоны функций с параметрами, которые либо соответствуют вызову аргументы точно или отличаются только способами, которые могут быть преодолены разрешено ограниченное преобразование. Не-выведенные аргументы позволяют полностью диапазон преобразования. Отметим также, что 13.3.3 указывает, что функция non-template будет иметь предпочтение перед шаблоном специализация, если две функции в противном случае одинаково хороши кандидаты на матч перегрузки.
от вышеуказанного мы получаем эти явные аргументы шаблона будут проверены, и если проверка будет успешной, то будет использоваться для синтеза специализации, которая будет добавлена к функциям-кандидатам для разрешения перегрузки. Таким образом, факт вы указываете явно X
не имеет значения для процесса.
также из стандарта C++§13.3.3 / p1.7 Лучшая жизнеспособная функция [окончена.спичка.best]:
F1
иF2
специализации шаблона функции, и функция шаблон дляF1
более специализирован, чем шаблон дляF2
согласно частичному правила заказа описаны в 14.5.6.2.
сейчас от §14.5.6.2 / p3 частичное упорядочение шаблонов функций [temp.функция.порядок] мы получаем, что в частичных параметрах заказа пакеты также играют, поэтому здесь нет проблем.
теперь:
template <typename X, typename... T>
auto bar(int, T...) -> void;
является более специализированным:
template <typename X, typename Check, typename... T>
auto bar(Check, T...) -> void;
зову:
bar<void>(7, "");
это не двусмысленно.
основываясь на вышеизложенном, я считаю, что это ошибка GCC.