Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

reinterpret_cast member function pointer to void(*&)()

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?

like image 569
walnut Avatar asked Nov 28 '19 18:11

walnut


People also ask

What is reinterpret_cast in C?

The reinterpret_cast operator converts a null pointer value to the null pointer value of the destination type.

Is reinterpret_cast safe?

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.

Is reinterpret cast compile time?

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.

Can you cast function pointers?

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.


1 Answers

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 object x, can be cast to the type “reference to T2” if an expression of type “pointer to T1” can be explicitly converted to the type “pointer to T2” using a reinterpret_­cast. The result is that of *reinterpret_­cast<T2 *>(p) where p is a pointer to x of type “pointer to T1”. ...

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.

like image 125
HolyBlackCat Avatar answered Oct 16 '22 20:10

HolyBlackCat