Member function pointers can not be reinterpret_cast
to function pointers. (GCC requires the -pedantic-errors
flag to enforce that, though.)
However GCC, Clang and MSVC seem to agree that casting a member function pointer to a reference to function pointer is ok. See the following example:
#include<type_traits>
struct A {
void f() {}
};
int main() {
auto x = &A::f;
auto y = reinterpret_cast<void(*&)()>(x);
// auto y = reinterpret_cast<void(*)()>(x);
static_assert(std::is_same_v<decltype(y), void(*)()>);
}
Godbolt here
This program compiles on all three compilers, but fails to compile on all (with pedantic flags) when the out-commented line is used instead of the previous one.
I don't see any rule in the standard allowing this conversion. Is the program ill-formed and the compilers fail to diagnose it or is the program well-formed?
If the latter, what is the exact conversion sequence, where does the standard allow it and can the function pointer be converted back to the original type in order to call it or is the use of the reference for initialization of y
already undefined behavior?
The reinterpret_cast operator converts a null pointer value to the null pointer value of the destination type.
The reinterpret_cast operator performs potentially unsafe type casts. It is most often used to cast a pointer to a different pointer type. Casting a pointer to a different pointer and back is usually safe and yields the original value.
The dynamic cast is the only that needs to be "calculated" in run-time. All other casts are calculated in compile-time. The machine code for a static_cast is a fixed function based on the type you are casting FROM and TO. For reinterpret_cast , the machine code can be resolved in compile-time as well.
Yes, it can. This is purpose of casting function pointers, just like usual pointers. We can cast a function pointer to another function pointer type but cannot call a function using casted pointer if the function pointer is not compatible with the function to be called.
reinterpret_cast<T&>(x)
is equivalent to *reinterpret_cast<T*>(&x)
.
In other words, reinterpret_cast<void(*&)()>(x)
performs type punning on the pointer itself.
Accessing the result of this cast violates strict aliasing and causes undefined behavior, as usual.
I don't see any rule in the standard allowing this conversion.
Here:
[expr.reinterpret.cast]/11:
A glvalue of type
T1
, designating an objectx
, can be cast to the type “reference toT2
” if an expression of type “pointer toT1
” can be explicitly converted to the type “pointer toT2
” using areinterpret_cast
. The result is that of*reinterpret_cast<T2 *>(p)
wherep
is a pointer tox
of type “pointer toT1
”. ...
Since reinterpret_cast
between pointers to object types (in your case, between pointers to pointers (to [member] functions)) is always allowed, it's also allowed in your case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With