I don't think the code is doing what you think it does. This line:
foo = reinterpret_cast<void(*)()>(Test());
means that you receive a void*
from Test()
. You then procede to reinterpret_cast
this pointer-to-object into a pointer-to-function. This is not allowed and therefore the code yields undefined behavior and therefore any output of the compiler is valid.
The relevant parts of the standard are
5.2.10 Reinterpret cast [expr.reinterpret.cast]
8 Converting a function pointer to an object pointer type or vice versa is conditionally-supported. The meaning of such a conversion is implementation-defined, except that if an implementation supports conversions in both directions, converting a prvalue of one type to the other type and back, possibly with dierent cv- qualification, shall yield the original pointer value.
9 The null pointer value (4.10) is converted to the null pointer value of the destination type. [Note: A null pointer constant of type std::nullptr_t
cannot be converted to a pointer type, and a null pointer constant of integral type is not necessarily converted to a null pointer value. — end note ]
and
4.10 Pointer conversions [conv.ptr]
1 A null pointer constant is an integral constant expression (5.19) prvalue of integer type that evaluates to 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 and is distinguishable from every other value of object pointer or function pointer type.
(emphasis mine)
Here's a reduced test case taking std::function
(and its possible bugs) out of the equation:
#include <iostream>
int main() {
using fp_t = void(*)();
void* vn = nullptr;
fp_t foo = reinterpret_cast<fp_t>(vn); // GCC: warning, Clang: silence
//fp_t foo = reinterpret_cast<fp_t>(nullptr); // error (GCC and Clang!)
std::cout << !!foo << std::endl;
}
Live example