You have provided the default type, but no default value. The function still requires two parameters, and the default_type
will be overridden by the deduced one, making it useless.
Do this:
template <typename U = default_type>
auto func(int x, U u = {}) { ... } // (1)
I can't support this by the exact standardese, but in short: U
is acquired at the template argument deduction stage (having no deduction rule - not considering default function arguments, therefore defaulted), which comes before the overload resolution stage, at which point the default function arguments are interpreted, already knowing the type of U
, which makes the list initialization valid.
Yes, you could as well write:
template <typename U = default_type>
auto func(int x, U u = U()) { ... } // (2)
or
template <typename U = default_type>
auto func(int x, U u = default_type()) { ... } // (3)
with slightly different semantics when explicitly providing the U
type (which I don't suppose you will):
func<not_the_default_type>(5);
Here, (1) and (2) are equivalent, but in (3), the construction of U
happens via constructing a default_type
temporary, which is then converted to not_the_default_type
.
Lastly, quite the opposite mistake would be to expect U
to be deduced here:
template <typename U>
auto func(int x, U u = default_type()) { ... }
which is not the case. See this Q&A.