stett
stett

Reputation: 1411

Why does overload resolution select pointer type for 0 but not 1, when it could select ellipses in either case?

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

Answers (3)

eerorika
eerorika

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

Bathsheba
Bathsheba

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

Nikos C.
Nikos C.

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

Related Questions