I have the following code sample:
template<typename T>
void print(T t) {
std::cout << t << std::endl;
}
template<typename Key, typename Value, typename F>
void traverse(std::map<Key, Value>& m, F f) {
for (auto&& [key, value] : m) {
f(value);
}
}
int main()
{
std::map<int, std::string> M;
// initializing the map
traverse(M, print);
}
Here the compiler erred with the following message:
could not deduce template argument for 'F'
The explicit traverse(M, print<std::string>);
solves the problem.
My question really is why compiler cannot deduce the template type for the print function?
As far as I understand, all the compile time information is available.
Template argument deduction works on the basis of the template parameters of the function, the signature of the function, and the types of the arguments provided. Nothing more. Even ignoring the fact that print
is a template function (and therefore doesn't have a type that could be used for deduction), there is nothing in the signature of traverse
that would give the compiler any idea that the type to deduce would be the type of print<std::string>
. Any such information would be in the function's definition.
A definition that doesn't exist yet and cannot exist until traverse
has been instantiated. And you can't instantiate a template until you have the template parameters. Which is what template argument deduction is intended to figure out.
Also, as previously mentioned, print
is not a function; it is the name of a template. It has no type; it isn't even a function. It is a means for generating a function, based on template parameters. Even if you tried to pass print
to a function that wasn't a template, the code still wouldn't work. The compiler can perform template argument deduction for functions only when you call them, not when you pass them as function arguments. In all non-deduced cases, you have to provide the template arguments directly.