Why am I allowed to explicitly instantiate a template specialization where the default argument is not implicitly convertible to the other type?

Viewed 92

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.

1 Answers

The default template parameter and its default value are specified for the function template func which means that they are considered only when the template is not instantiated with any type and value.

So func(std::string("test")); call uses the explicit instantiation of the template with std::string and succeed.

Whereas func<std::string>(); will fail because explicit instantiation of the template with std::string is used but the default value of the parameter is 1 (which is an int).

This is equivalent to:

func<std::string>(1);

And the compiler (GCC 8.2) reports the same error for both these calls.

<source>:18:23: note:   cannot convert '1' (type 'int') to type 'std::__cxx11::basic_string<char>'

See demo here.

Related