I'm reading Unexpected value using random number generator as a function in C++ and the comments and current answer say that the user is outputting the address of the function. That sounded reasonable. I assumed that a function-to-pointer conversion was occurring and therefore matching the const void*
overload, however upon testing it myself, I get different results in GCC/Clang vs MSVC. The following test program:
#include <iostream>
void test()
{
}
void func(bool)
{
std::cout << "bool";
}
void func(const void*)
{
std::cout << "const void*";
}
int main()
{
func(test);
}
outputs bool
in GCC/Clang (coliru
)
and const void*
in MSVC (rextester
warning live collaboration link)
N3337 says:
[conv.func]
An lvalue of function type
T
can be converted to a prvalue of type "pointer toT
." The result is a pointer to the function.
[conv.bool]
A prvalue of arithmetic, unscoped enumeration, pointer, or pointer to member type can be converted to a prvalue of type
bool
. A zero value, null pointer value, or null member pointer value is converted tofalse
; any other value is converted totrue
. A prvalue of typestd::nullptr_t
can be converted to a prvalue of type bool; the resulting value isfalse
.
So a pointer which is not a null pointer value converted to bool should equal true
, explaining the warning given by GCC/Clang.
Then Table 12 Conversions under [over.ics.scs] gives a function-to-pointer conversion an "Exact Match" rank and boolean conversions "Conversion" rank. [over.ics.rank]/4 then says:
Standard conversion sequences are ordered by their ranks: an Exact Match is a better conversion than a Promotion, which is a better conversion than a Conversion. Two conversion sequences with the same rank are indistinguishable unless one of the following rules applies:
— A conversion that does not convert a pointer, a pointer to member, or
std::nullptr_t
tobool
is better than one that does.— [...]
I am not a language lawyer so I hope that I quoted the right sections.
However MSVC will call the const void*
overload even if the bool
overload is absent, and vice versa: GCC/Clang will call the bool
overload even if the const void*
overload is absent. So I'm not clear on the conversions here. Can somebody clear this up for me?