Вычитание шаблона C++ не работает

Для следующего кода:

#include<functional>
template<typename T>
void f(std::function<void(T)> g) {
}

template<typename T>
void g(T x) {
}

int main() {
   f(&g<int>);
}

Компилятор C++14 выдает ошибку:

 no matching function for call to 'f(<unresolved overloaded function type>)'
     f(&g<int>);

Мне любопытно, почему вывод аргументов шаблона здесь не работает. Кажется, что, учитывая, что аргумент g имеет тип int, мы можем сделать вывод, что аргумент f имеет тип std::function<void(int)>, и поэтому T = int в ф. Почему этого не происходит? Меня интересует соответствующий раздел стандарта C++, который объясняет это. Встречается ли T в не выводимом контексте здесь?

Следующий подобный код компилируется:

#include<vector>
template<typename T>
void f(std::vector<T> vec) { 
}


int main() {
    f(std::vector<int>{});
}

Так что это не угловые скобки, которые создают не выводимый контекст.

2 ответа

Решение

Ваша функция ожидает аргумент типа std::function, но вместо этого вы передаете ему указатель на функцию. &g<int> конвертируется в std::function тип параметра, но для вывода аргумента шаблона требуются точные совпадения (за исключением корректировок, разрешенных [temp.deduct.call] / 2,3,4), определенные пользователем преобразования не рассматриваются.

Пишу f(std::function<void(int)>(g<int>)) будет работать, потому что вы сейчас передаете std::function, так что вывод аргумента шаблона будет успешным.

f<int>(&g<int>) также работает, потому что вы сейчас явно указали T, он больше не участвует в выводе аргументов шаблона и пользовательские преобразования будут предприниматься.

Тип &g<int> является void(*)(int), Поэтому компилятор пытается сгенерировать функцию с подписью void f<>(void(*)(int)) что он не может сделать из вашего шаблона. Тип std::function<void(int)> это совершенно другой тип.

В вашем подобном коде объект std::vector<int>{} имеет тип std::vector<int> поэтому компилятор пытается сгенерировать функцию void f<>(std::vector<int>) что он может сделать из предоставленного шаблона путем выведения T быть int,

При указании f<int>компилятору не нужно выводить тип, и поэтому он не может этого не делать. Более того, хотя в выведенном контексте не учитываются неявные преобразования, они рассматриваются в не выводимом контексте. Таким образом, предоставляя тип явно и, таким образом, превращая аргумент функции в не выводимый контекст, вы позволяете компилятору использовать неявное преобразование для инициализации std::function<void(int)> спорить с g<int>,

Другие вопросы по тегам