Reputation: 620
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?
Upvotes: 0
Views: 235
Reputation: 62636
Parameters with defaults are still positional. Your example is the same as
void foo(int i=8, const char * c="hello world")
{
std::cout << "Default param \t= " << i << "\n";
std::cout << "Additional param \t= " << c << "\n";
}
int main()
{
foo(); // 8 "hello world"
foo(1, "str1"); // 1 "str1"
foo("str3"); // ERROR: parameter mismatch
return 0;
}
Upvotes: 5
Reputation: 180500
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.
Upvotes: 5
Reputation: 41760
This don't work for the same reasons why this won't work:
void f(int = 0, const char*);
int main() {
f("test")
}
If you read the error, you'll see that the compiler cannot convert a string literal into a int
. And this is true, the first parameter is a int, and you sent it a string literal.
Parameters cannot be rebound to other position, regardless if there's a default argument or not.
Upvotes: 3