Вывод типа для нежизнеспособных шаблонов функций

В его ответ в этот вопрос и раздел комментариев, Йоханнес Шауб говорит, что есть «ошибка совпадения» при попытке сделать вывод типа шаблона для шаблона функции, который требует больше аргументов, чем было передано:

template<class T>
void foo(T, int);

foo(42); // the template specialization foo<int>(int, int) is not viable

В контексте другого вопроса важно то, успешно ли выполняется вывод типа для шаблона функции (и происходит ли подстановка):

template<class T>
struct has_no_nested_type {};

// I think you need some specialization for which the following class template
// `non_immediate_context` can be instantiated, otherwise the program is
// ill-formed, NDR
template<>
struct has_no_nested_type<double>
{ using type = double; };

// make the error appear NOT in the immediate context
template<class T>
struct non_immediate_context
{
using type = typename has_no_nested_type<T>::type;
};template<class T>
typename non_immediate_context<T>::type
foo(T, int) { return {}; }

template<class T>
bool foo(T) { return {}; }int main()
{
foo(42);      // well-formed? clang++3.5 and g++4.8.2 accept it
foo<int>(42); // well-formed? clang++3.5 accepts it, but not g++4.8.2
}

При создании первого шаблона функции foo за T == int, замена производит недопустимый тип не в непосредственном контексте foo, Это приводит к серьезной ошибке (вот что связанный вопрос около.)

Однако при сдаче foo вывести его шаблон-аргумент, g ++ и clang ++ соглашаются, что создание экземпляров не происходит. Как Йоханнес Шауб объясняет, это потому, что есть «ошибка совпадения».

Вопрос: Что такое «ошибка соответствия», и где и как она указана в Стандарте?

Альтернативный вопрос: почему есть разница между foo(42) а также foo<int>(42) для g ++?


Что я нашел / попробовал до сих пор:

[over.match.funcs] / 7 и [temp.over] описывают особенности разрешения перегрузки для шаблонов функций. Последние, кажется, требуют замены параметров шаблона для foo,

Интересно, что [over.match.funcs] / 7 запускает процесс, описанный в [temp.over] до проверка жизнеспособности шаблона функции (специализация).
Точно так же вычитание типа не учитывает, скажем, аргументы функции по умолчанию (кроме того, что делает их не выводимым контекстом). Насколько я могу судить, это не касается жизнеспособности.

Другим, возможно, важным аспектом является способ определения типа вывода. Он действует на параметры одной функции, но я не вижу, где проводится различие между типами параметров, которые содержат / зависят от параметров шаблона (например, T const&) и те, которые не (как int).

Тем не менее, g ++ делает различие между явным указанием параметра шаблона (серьезная ошибка) и разрешением их вывода (ошибка вывода / SFINAE). Зачем?

3

Решение

Я подытожил процесс, описанный в 14.8.2.1p1

Вывод аргумента шаблона выполняется путем сравнения каждого типа параметра шаблона функции (назовите его P) с типом соответствующего аргумента вызова (назовите его A), как описано ниже.

В нашем случае мы имеем для P (T, int) и для А мы имеем (int), Для первой пары P / A, которая T против intмы можем соответствовать T в int (согласно процессу, описанному в 14.8.2.5). Но для второй «пары» мы имеем int но не имеют аналогов. Таким образом, вычет не может быть сделан для этой «пары».

Таким образом, согласно 14.8.2.5p2, «если выведение типа не может быть выполнено для любой пары P / A, …, шаблон
вывод аргумента не удался.

Тогда вы никогда не дойдете до того момента, когда подставите аргументы шаблона в шаблон функции.

Все это, вероятно, может быть более точно описано в Стандарте (IMO), но я считаю, что именно так можно реализовать вещи, соответствующие реальному поведению Clang и GCC, и это кажется разумной интерпретацией Standardese.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]