Because of 8.3.6 ([dcl.fct.default])/4,
In a given function declaration, each parameter subsequent to a parameter with a default argument shall have a default argument supplied in this or a previous declaration or shall be a function parameter pack.
the following should compile:
#include <iostream>
template<typename ...Ts>
void foo(int i=8, Ts... args)
{
std::cout << "Default parameters \t= " << i << "\n";
std::cout << "Additional params \t= " << sizeof...(Ts) << "\n";
}
int main()
{
foo(); // calls foo<>(int)
foo(1, "str1", "str2"); // calls foo<const char*, const char*>(int, const char*, const char*)
foo("str3"); // ERROR: does not call foo<const char*>(int, const char*)
return 0;
}
But it does not compile due to foo("str3")
which confuses the compiler. It complains that there is no matching function for call to foo(const char*)
and that it cannot convert "str3"
(type const char*
) to type int
.
I understand that one can work around this problem by resorting to function overloading or using the named parameter idiom (cf. where to place default value parameter in variable-length function in c++? and default arguments and variadic functions). However, I would like to know if the compiler is just stupid or if there is a genuine reason why the intended behaviour in the code example above is not implemented. In other words, why does the compiler complain even if I explicitly instantiate the function as foo<const char*>(int, const char*)
? It's as if the explicit instantiation simply ignores the value of the default parameter. Why?
The standard you are quoting is just saying it is legal to form
template<typename ...Ts>
void foo(int i=8, Ts... args)
When you call it though, you still have to pass an int
as the first parameter otherwise the function won't be considered during overload resolution. When you do
foo("str3");
the compiler is going to look for any function foo
that takes a const char*
or a const char(&)[5]
since that is the only parameter. That means your function is complete ignored because it expects and int
for the first parameter or no parameters at all.