Вычитание шаблона 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>
,