Reputation: 1411
I have the following snippet of code:
void eval(void*) { std::cout << "hello world\n"; }
void eval(...) { }
int main(int argc, char *argv[])
{
std::cout << "0: "; eval(0);
std::cout << "1: "; eval(1);
return 0;
}
which gives the output:
0: hello world
1:
My question is: Why does overload resolution select the void*
version of eval
instead of the ...
version for 0
, but not for 1
? It seems like in both cases it could infer that the argument is an int and take the variadic version.
Upvotes: 5
Views: 125
Reputation: 238421
Why does overload resolution select the void* version of eval instead of the ... version for 0
Because 0 is a null pointer constant.
but not for 1?
Because 1 is not a null pointer constant.
The standard rule:
[conv.ptr]
A null pointer constant is an integer literal ([lex.icon]) with value zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type ...
It seems like in both cases it could infer that the argument is an int and take the variadic version.
The C-style variadic argument is the least preferred choice by overload resolution, even when it doesn't need conversion of the argument type that another candidate would require. As long as there is any other valid candidate, the other candidate is chosen. In this case, there is the void*
overload which is valid for 0 but not for 1.
If you had an overload eval(int)
, that would be chosen for both 0 and 1.
P.S. This property of overload resolution of C-style variadic arguments is sometimes used for implementing type traits by dark template magicians.
Upvotes: 4
Reputation: 234815
The int
octal literal 0
is implicitly convertible to the void*
pointer type, but 1
is not. This is a pre-C++11 thing (nullptr
and its type nullptr_t
were introduced in C++11) and is here to stay else existing code would break.
Overload resolution favours a non-variadic function over a variadic one.
Putting these two things together explains your program output.
Upvotes: 4
Reputation: 51910
Because of backwards compatibility, 0
is convertible to a pointer. It was used as the NULL pointer. Nowadays nullptr
is used, but 0
still needs to be convertible, otherwise old code would not compile anymore.
If you compile with the highest warning level enabled in your compiler, chances are the compiler will warn you whenever 0
is used as a pointer.
Upvotes: 7