I was trying this code snippet
#include <cstddef>
#include <cstdio>
void f(int* ptr){
std::printf("int*\n");
}
void f(int val){
std::printf("int\n");
}
int main() {
f(NULL);
}
This errors out on both GCC and CLANG but MSVC prints int
. As per my reading of [conv.ptr]
, since a null pointer constant (which is what NULL
is) of integral type can be converted to a pointer type, it should be ambiguous for the compiler while selecting the appropriate function since it can bind both to int
and int*
. I confirmed that all these compilers have NULL
implemented as an integral type via
#if defined(_MSC_VER)
static_assert(std::is_same<decltype(NULL), int>(), "");
#else
static_assert(std::is_same<decltype(NULL), long>(), "");
#endif
So, is this an MSVC bug or am I missing something and compilers are not expected to throw an error in such cases?
EDIT: I'm aware that nullptr
is the way to gauge null-ness, but this question is merely out of curiosity and an attempt at understanding the specification around it.
CodePudding user response:
NULL
is an old C-compatibility macro. It's usually defined as the plain integer 0
. Because of that f(int)
will be called.
In C you should be using nullptr
for null pointers.
CodePudding user response:
since a null pointer constant (which is what NULL is) of integral type can be converted to a pointer type, it should be ambiguous for the compiler while selecting the appropriate function since it can bind both to int and int*.
It's only ambiguous when the overload resolution has to choose between two equivalent conversion sequences. E.g. from 0L
to int
or int*
.
But overload resolution is trivial when one of the overloads is a perfect match. And as it happens, 0
is a perfect match for int
.
Both 0
and 0L
have integral type, so all compilers are correct.
Bonus:
void f(std::integral auto val) {
std::printf("integral\n");
}
Perfect match after template instantiation.