See the following code:
#include <iostream>
template<typename T = int>
void func(T t = 1)
{
std::cout << t << std::endl;
}
template void func<int>(int); // Explicit instantion of `int`
template void func<std::string>(std::string); // Explicit instantiation of `std::string` -- why does this not give the same error as below?
int main()
{
func(); // Outputs "1" - OK
func(std::string("test")); // Outputs "test" - OK
// func<std::string>(); // Explicit instantiation - Fails (as expected!): could not convert '1' from 'int' to 'std::string'
}
I would have thought that the template void func<std::string>(std::string); line would be illegal, as the default int argument can't be converted implicitly to std::string (similar to how I get a compilation error on the last invocation), and that I would have to resort to the solution outlined in this answer.
When I have a function template with a default argument, why am I allowed to explicitly instantiate a template specialization where the default argument is not implicitly convertible to the other type? This turns out to be exactly what I wanted, but I'm curious to know how the compiler figures things out.