Подтвердить что ты не робот

Как работает вывод аргумента шаблона, когда в качестве аргумента используется перегруженная функция?

Это более сложный вопрос, упомянутый в Как работает разрешение перегрузки, когда аргумент является перегруженной функцией?

Ниже код компилируется без каких-либо проблем:

void foo() {}
void foo(int) {}
void foo(double) {}
void foo(int, double) {}

// Uncommenting below line break compilation
//template<class T> void foo(T) {}

template<class X, class Y> void bar(void (*f)(X, Y))
{
    f(X(), Y());
}

int main()
{
    bar(foo);
}

Это не сложная задача для вывода аргумента шаблона - существует только одна функция foo(), которая принимает два аргумента. Однако раскомментирование перегрузки шаблона foo() (которая по-прежнему имеет только один параметр) прерывает компиляцию по очевидной причине. Компиляция не работает как с gcc 5.x/6.x, так и с clang 3.9.

Можно ли это объяснить правилами разрешения перегрузки/вывода аргумента шаблона или он должен быть квалифицирован как дефект в этих компиляторах?

4b9b3361

Ответ 1

Как указано в ответе на ваш связанный вопрос:

[temp.deduct.call]/6: Когда P - это тип функции, указатель на тип функции или указатель на тип функции-члена:

- Если аргумент представляет собой набор перегрузки, содержащий один или несколько шаблонов функций, параметр обрабатывается как невыводимый контекст.

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

[temp.deduct.type]/4: [...] Если параметр шаблона используется только в не выводимых контекстов и явно не указано, вывод аргумента шаблона не выполняется.

И этот неудачный вывод дает вам вашу ошибку. Обратите внимание: если вы явно указываете аргументы, код успешно компилируется:

bar<int,double>(foo);

Живая демонстрация