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


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

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

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() (которая все еще имеет только один параметр), компиляция прерывается для no очевидная причина. Компиляция завершается неудачей как с gcc 5.х / 6.х и лязг 3.9.

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

1 ответ:

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

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

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

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

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

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

bar<int,double>(foo);

Live demo